I'm trying to avoid the use of notifications with delegation. I need to reload a tableView selecting a row on another tableView, but reloadData() is not working.
protocol GroupDelegate {
func groupDidSelectRow(selectedRow: Int)
}
class GroupTableView: NSTableView, NSTableViewDelegate, NSTableViewDataSource, NSMenuDelegate {
var groupDelegate:GroupDelegate?
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
self.delegate = self
self.dataSource = self
self.groupDelegate = TemplateTableView()
}
func tableViewSelectionDidChange(_ notification: Notification) {
groupDelegate?.groupDidSelectRow(selectedRow: self.selectedRow)
}
}
class TemplateTableView: NSTableView, NSTableViewDelegate, NSTableViewDataSource, GroupDelegate {
var groupSelectedRow = 0
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
self.delegate = self
self.dataSource = self
}
func groupDidSelectRow(selectedRow: Int) {
groupSelectedRow = selectedRow
reloadData() // This line is not working
}
}
Related
I'm having trouble passing data after run App.I'm pretty much trying to change a label from the previous view controller after selecting a table view cell
Could anyone help me go about there error?
view controller
class AircraftSearch: UIViewController ,SendbackDelegate{
#IBOutlet weak var Mabda: UIButton!
#IBOutlet weak var maghsad: UIButton!
#IBOutlet weak var labelcity: UILabel!
var Airurl = NSURL()
var ScrOrDstArray = [MabdaAndMaghsad]()
var origin = [String]() // save mabda
var purpose = [String]() // save maghsad
var sendDataToTableview = [String]()
override func viewDidLoad() {
super.viewDidLoad()
GetPassCity()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func selectMabda(sender: AnyObject) {
sendDataToTableview = origin
performSegueWithIdentifier("SelectedCellSegue", sender: sender)
}
#IBAction func selectMaghsad(sender: AnyObject) {
sendDataToTableview = purpose
print(sendDataToTableview)
performSegueWithIdentifier("SelectedCellSegue", sender: sender)
}
func originAndpurpose() {
let dataCity = ScrOrDstArray
for i in dataCity{
if i.SrcOrDst == true{
origin.append(i.Name)
}else{
purpose.append(i.Name)
}
}
}
func GetPassCity(){
let actInd : UIActivityIndicatorView = UIActivityIndicatorView(frame: CGRectMake(0,0, 50, 50)) as UIActivityIndicatorView
actInd.center = self.view.center
actInd.hidesWhenStopped = true
actInd.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.Gray
view.addSubview(actInd)
actInd.startAnimating()
NSURLSession.sharedSession().dataTaskWithURL(Airurl){ ( data ,response ,error) in
if error != nil{
print("A")
print(error!)
}else{
do{
//readin data from Server
let posts = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! [[String:AnyObject]]
//save data
for post in posts{
var postCity:MabdaAndMaghsad?
if let Id = post["Id"] as? Int ,
let nameCity = post["Name"] as? String ,
let SrcOrDst = post["SrcOrDst"] as? Bool
{
postCity = MabdaAndMaghsad(ID: Id, Name: nameCity, SrcOrDst: SrcOrDst)
}
self.ScrOrDstArray.append(postCity!)
}
//===============
dispatch_async(dispatch_get_main_queue()){
actInd.stopAnimating()
self.originAndpurpose()
print(self.origin)
print("=======")
// print(self.purpose)
}
}catch let error as NSError{
print("B")
print(error)
}
}
}.resume()
}
func sendNameToPreviousVC(SelectCity: String) {
labelcity.text = SelectCity
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "SelectedCellSegue" {
if let VC = segue.destinationViewController as? SelectedCity {
VC.toTake = sendDataToTableview
VC.delegate = self
}
}
}
}
and tableview Controller
import UIKit
protocol SendbackDelegate:class {
func sendNameToPreviousVC(City:String)
}
class SelectedCity: UITableViewController {
var toTake = [String]()
var selecteCity = String()
weak var delegate: SendbackDelegate? = nil
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return toTake.count ?? 0
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("stcell", forIndexPath: indexPath) as? mAndMCell
let nameCity = toTake[indexPath.row]
print(nameCity)
cell!.nameCityLabel.text = nameCity
return cell!
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRowAtIndexPath(indexPath) as! mAndMCell!
selecteCity = currentCell.nameCityLabel!.text as String!
sendBackIdCity(selecteCity)
navigationController?.popViewControllerAnimated(true)
}
func sendBackIdCity(name: String){
self.delegate?.sendNameToPreviousVC(name)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "backCitySegue"{
var VCOne = segue.destinationViewController as? AircraftSearch
VCOne.delegate = self
}
}
}
error is line VCOne.delegate = self
error = Value of type 'AircraftSearch?' has no member 'delegate'
The line should probably be
self.delegate = VCOne
since self is the SelectedCity which has the delegate property and VCOne is of type AircraftSearch and therefore is a SendbackDelegate!
I have these facebook interstitial ads and when I call them in my GameScene they dont show up. They work perfectly when I call them in the GameViewController but not in my GameScene. Can someone tell me what Im doing wrong with my code?
//GameViewController.swift
class GameViewController: UIViewController, FBInterstitialAdDelegate {
let interstitialFBAD: FBInterstitialAd = FBInterstitialAd(placementID: "65543456456456_454345345454534")
override func viewDidLoad() {
super.viewDidLoad()
}
//CALL THIS IN MY GAMESCENE.
func loadFBInterstitialAd() {
interstitialFBAD.delegate = self
interstitialFBAD.loadAd()
}
func interstitialAdDidLoad(interstitialAd: FBInterstitialAd!) {
interstitialFBAD.showAdFromRootViewController(self)
}
//GameScene.swift
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches {
let location = touch.locationInNode(self)
let node = self.nodeAtPoint(location)
if node.name == "retry" {
GameViewController().loadFBInterstitialAd()
}
}
}
In viewDidLoad of GameViewController register for a notification, and later from the GameScene post a notification when you want the ad to appear.
so your viewDidLoad will have the following extra line
NSNotificationCenter.defaultCenter().addObserver(self, selector: "loadFBInterstitialAd", name: "loadAd", object: nil)
then write a method in Gamescene
func showAdNow() {
NSNotificationCenter.defaultCenter().postNotificationName("loadAd", object: nil)
}
now in Gamescene.swift replace the line
GameViewController().loadFBInterstitialAd()
with
showAdNow()
You try:
//GameViewController.swift
class GameViewController: UIViewController, FBInterstitialAdDelegate {
let interstitialFBAD: FBInterstitialAd = FBInterstitialAd(placementID: "65543456456456_454345345454534")
var scene: GameScene!
override func viewDidLoad() {
super.viewDidLoad()
let skView = view as! SKView
skView.multipleTouchEnabled = false
scene = GameScene(size: skView.bounds.size)
scene.scaleMode = .AspectFill
scene.view?.userInteractionEnabled = true
skView.presentScene(scene)
scene.gvcDelegate = self
}
//GameScene.swift
class GameScene: SKScene {
gvcDelegate: GameViewController?
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches {
let location = touch.locationInNode(self)
let node = self.nodeAtPoint(location)
if node.name == "retry" {
gvcDelegate.loadFBInterstitialAd()
}
}
}
Goodluck!
I have an app that has two ViewControllers. On the first there is a count of current speed in realtime through CLLocationManager. Also there is a label that shows current speed with update by timer (NSTimer). In second ViewController there is another Label, where this current speed has to be shown too. It shows it, but don't update. I tried to set second timer (different ways: in first VC, in second VC - there is always was an error or just nothing).
Will be grateful for help, thanks!
First VC
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
#IBOutlet weak var mapView: MKMapView!
#IBOutlet weak var currentSpeedLabel: UILabel!
var manager = CLLocationManager()
var currentSpeed: CLLocationSpeed = CLLocationSpeed()
var timer = NSTimer()
override func viewDidLoad() {
super.viewDidLoad()
mapView.mapType = MKMapType.Hybrid
trackingMe()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func HUDMapView(sender: AnyObject) {
speedCount()
}
#IBAction func findMe(sender: AnyObject) {
trackingMe()
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userLocation: CLLocation = locations[0] as CLLocation
manager.stopUpdatingLocation()
let location = CLLocationCoordinate2D(latitude: userLocation.coordinate.latitude, longitude: userLocation.coordinate.longitude)
let span = MKCoordinateSpanMake(0.05, 0.05)
let region = MKCoordinateRegion(center: location, span: span)
mapView.setRegion(region, animated: true)
}
func trackingMe() {
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
mapView.showsUserLocation = true
currentSpeedUpdate()
}
func currentSpeedUpdate() {
timer = NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: Selector("speedCount"), userInfo: nil, repeats: true)
}
func speedCount() {
currentSpeed = manager.location!.speed
currentSpeedLabel.text = String(format: "%.0f km/h", currentSpeed * 3.6)
}
override func prepareForSegue(segue: (UIStoryboardSegue!), sender: AnyObject!) {
let speedController = segue.destinationViewController as! speedViewController
currentSpeed = manager.location!.speed
speedController.showSpeed = currentSpeedLabel.text
}
}
Second VC
import UIKit
class speedViewController: UIViewController {
#IBOutlet weak var secondSpeedLabel: UILabel!
var showSpeed: String!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
secondSpeedLabel.text = showSpeed
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func back(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil)
}
}
Project Link
You could use a Singleton to hold the LocationManager. Then you can access it from all over your app. When you move to a second VC you can either change the delegate to the second VC or just get the needed data manually.
Remember that a delegate can only point to one "receiver". Changing the delegate will stop updates in the first VC. but since it is now a Singleton you can also store information in there about past locations / speeds. When dismissing the second VC get the stored data and update.
This will keep running until you call stop()
The code was simplified a bit to illustrate the idea.
VC Code:
import UIKit
import CoreLocation
class ViewController: UIViewController, TrackerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
Tracker.shared.delegate = self
Tracker.shared.start()
}
func speedUpdate(speed: CLLocationSpeed) {
print(speed)
}
}
Singleton Code:
import UIKit
import MapKit
import CoreLocation
class Tracker: NSObject, CLLocationManagerDelegate {
static var shared = Tracker()
private var manager = CLLocationManager()
private var timer = NSTimer()
var region : MKCoordinateRegion?
var currentSpeed: CLLocationSpeed = CLLocationSpeed()
weak var delegate : TrackerDelegate?
private override init() {
super.init()
manager.delegate = self
manager.requestWhenInUseAuthorization()
}
internal func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
manager.stopUpdatingLocation()
let userLocation: CLLocation = locations[0] as CLLocation
let coordinates2D = CLLocationCoordinate2D(latitude: userLocation.coordinate.latitude, longitude: userLocation.coordinate.longitude)
let span = MKCoordinateSpanMake(0.05, 0.05)
region = MKCoordinateRegion(center: coordinates2D, span: span)
currentSpeed = userLocation.speed
guard let del = delegate else {
return
}
del.speedUpdate(currentSpeed)
}
func start() {
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.startUpdatingLocation()
timer = NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: Selector("loopUpdate"), userInfo: nil, repeats: true)
}
func stop() {
timer.invalidate()
}
internal func loopUpdate() {
// restart updating
manager.startUpdatingLocation()
}
}
Delegate for the Singleton:
Add more functions, or more values to the current function to get more feedback.
protocol TrackerDelegate : class {
func speedUpdate(speed:CLLocationSpeed)
}
I have 2 ViewControllers: ViewController1, ViewController2. An "Add" button in ViewController1 will bring up ViewController2. User will then enter in values into ViewController2 which will then be passed back into ViewController1 by prepareforsegue. These values are then append onto the properties of type array in viewcontroller1.
This is being repeated, whereby the user continue pressing the add button to bring up ViewController2 from ViewController1, and then add in new values to be appended onto the properties of array type in ViewController1 via prepareforsegue.
However this is not the case after the first set of values being appended from ViewController2. The second set of values will overwrite the first set of values.
Example.
After the first passed -> force =[1], stiffness[1]
After the second passed -> force=[2], stiffness[2]
I will want this -> force = [1,2], stiffness[1,2]
I want to continue adding until -> force = [1,2,3,4,5], stiffness[1,2,3,4,5]
ViewController1
class ViewController1: UITableViewController, UITableViewDataSource {
var force = [Float]()
var stiffness = [Float] ()
#IBAction func Add(sender: AnyObject) { }
}
ViewController2
class ViewController2: UIViewController {
var forceVar : Float = 0.0
var stiffVar : Float = 0.0
#IBAction func submit(sender: AnyObject) {
self.performSegueWithIdentifier("springSubmit", sender: sender)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if(segue.identifier == "springSubmit") {
var svcSubmitVariables = segue.destinationViewController as ViewController1
svcSubmitVariables.force.append(forceVar)
svcSubmitVariables.stiffness.append(stiffVar)
}
The performSegueWithIdentifier method will always initialize new view controller so in your example view controller that showed ViewController2 is different object from object initialized after submitting data and ofc this newly initialized object will have only initialize values. To achieve what you are looking for you will need to declare a function on your ViewController1 that will append data to your arrays, pass that function to ViewController2 and call it on submit method so your view controllers would look similar like these:
ViewController1
class ViewController1: UITableViewController, UITableViewDataSource {
var force = [Float]()
var stiffness = [Float] ()
override func viewWillAppear(animated: Bool) {
//check if values are updated
println(force)
println(stiffness)
}
#IBAction func Add(sender: AnyObject) {
self.performSegueWithIdentifier("viewController2", sender: sender)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if(segue.identifier == "viewController2") {
var addVariables = segue.destinationViewController as ViewController2
addVariables.submitFunc = appendData
}
}
func appendData(newForce:Float,newStiffness:Force){
force.append(newForce)
stiffness.append(newStiffness)
}
}
ViewController2
class ViewController2: UIViewController {
var forceVar : Float = 0.0
var stiffVar : Float = 0.0
var submitFunc:((newForce:Float,newStiff:Float)->())!
#IBAction func submit(sender: AnyObject) {
submitFunc(forceVar,stiffVar)
self.dismissViewControllerAnimated(false, completion: nil)
}
}
ViewController
import UIKit
class ViewController: UITableViewController, UITableViewDataSource {
var springNumber:NSInteger = 0
var force = [Float]()
var stiffness = [Float] ()
// MARK: UITableViewDataSource
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
return springNumber
}
override func tableView(tableView: UITableView,
cellForRowAtIndexPath
indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell")
as UITableViewCell
cell.textLabel!.text = "Spring \(indexPath.row)"
return cell
}
func fwall() -> Float {
for rows in 0..<(springNumber+1) {
force[0] = force[0] + force[rows]
}
force[0] = -(force[0])
return force[0]
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
title = "Springs' Variables"
tableView.registerClass(UITableViewCell.self,
forCellReuseIdentifier: "Cell")
if(springNumber==0) {
force.append(0.0) }
println(force)
println(stiffness)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//Adding Values
#IBAction func Add(sender: AnyObject) {
self.performSegueWithIdentifier("addSpring", sender: sender)
}
#IBAction func solve_Pressed(sender: AnyObject) {
self.fwall()
self.performSegueWithIdentifier("Solve", sender: sender)
}
func appendData (newForce: Float, newStiffness:Float, newSpring: NSInteger) {
force.append(newForce)
stiffness.append(newStiffness)
springNumber = newSpring
println(springNumber)
println(force)
println(stiffness)
}
override func prepareForSegue ( segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "addSpring") {
var addVariables = segue.destinationViewController as SpringTableViewControllerInsertVariables
addVariables.submitFunc = appendData
}
if (segue.identifier == "Solve") {
var svcViewController2 = segue.destinationViewController as ViewController2
svcViewController2.forceView2 = self.force
svcViewController2.stiffView2 = self.stiffness
svcViewController2.springNumView2 = self.springNumber
}
if (segue.identifier == "showDetail") {
}
}
}
Code for springTableViewControllerInsertVariables
import UIKit
class SpringTableViewControllerInsertVariables: UIViewController {
var forceVar : Float = 0.0
var stiffVar : Float = 0.0
var springNum : NSInteger = 0
var submitFunc: ((newForce:Float,newStiff:Float,newSpring:NSInteger)->())!
#IBOutlet weak var image: UIImageView!
var imageArray :[UIImage] = [UIImage(named: "springAtWall.jpg")!, UIImage(named:"spring.jpg")!]
override func viewDidLoad() {
if(springNum == 0) {image.image = imageArray[0] }
else {image.image = imageArray[1] }
}
#IBOutlet weak var force: UILabel!
#IBOutlet weak var forceEntered: UITextField!
#IBOutlet weak var stiffness: UILabel!
#IBOutlet weak var stiffnessEntered: UITextField!
#IBAction func checkboxed(sender: AnyObject) {
//when checkedboxed is checked here.
//1)UIImage is changed
//2)calculate2 function is used for calculate1
}
#IBAction func submit(sender: AnyObject) {
//might not work because springNum will be initialise to zero when this viewcontroller starts...
forceVar = (forceEntered.text as NSString).floatValue
stiffVar = (stiffnessEntered.text as NSString).floatValue
springNum = springNum + 1
submitFunc(newForce: forceVar ,newStiff: stiffVar, newSpring: springNum)
self.dismissViewControllerAnimated(false, completion: nil)
}
}
I subclassed UISegmentedControl in order to trigger the valueChanged method which works fine. Now when I select a segment the index is always -1.
I am on Xcode 6 beta 4, I can't find what I am doing wrong.
The subclass:
import UIKit
class MySegCotrl: UISegmentedControl {
init(coder aDecoder: NSCoder!) {
super.init(coder: aDecoder)
}
override func touchesEnded(touches: NSSet!, withEvent event: UIEvent!) {
let current = self.selectedSegmentIndex
super.touchesBegan(touches, withEvent: event)
println("Current:\(current)")
println("Self.selectedSegmentIndex:\(self.selectedSegmentIndex)")
if current == self.selectedSegmentIndex {
self.sendActionsForControlEvents(UIControlEvents.ValueChanged)
}
}
}
The valueChanged method in my UIViewController class
#IBOutlet var segCotrRelevanz: MySegCotrl!
#IBAction func relevanChanged(sender: AnyObject) {
println("sender.selectedSegmentIndex:\(sender.selectedSegmentIndex)")
println("segCotrRelevanz.selectedSegmentIndex:\(segCotrRelevanz.selectedSegmentIndex)")
if sender.selectedSegmentIndex == segCotrRelevanz.selectedSegmentIndex {
println("Same")
}
}
The output:
Current:-1
Self.selectedSegmentIndex:-1
sender.selectedSegmentIndex:-1
segCotrRelevanz.selectedSegmentIndex:-1
Same
Try change method to touchesBegan not touchesEnded, left all as it should be:
override func touchesBegan(touches: NSSet!, withEvent event: UIEvent!) {
let current = self.selectedSegmentIndex
super.touchesBegan(touches, withEvent: event)
println("Current:\(current)")
println("Self.selectedSegmentIndex:\(self.selectedSegmentIndex)")
if current == self.selectedSegmentIndex {
self.sendActionsForControlEvents(UIControlEvents.ValueChanged)
}
}