24008


NSNotification 通知が失敗し、指定したMapが表示されません。（日本地図が表示されます）  
コードは以下の通りです。問題点を教えて頂けませんでしょうか。  
よろしくお願いいたします。

《やりたいこと》  
1.ViewController 条件分岐  
2.NSTimer → 3秒後に画面遷移を設定  
NSNotification → userInfoに数値データをもたせ、SecondViewControllerに通知を送る  
3.SecondViewController 通知を受け取り、switchで受け取った数値を選択、Mapを表示させる

ViewController.swift

[code]

    import UIKit
    
    class ViewController: UIViewController {
    
      var timer:NSTimer = NSTimer()
    
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
    @IBAction func didTouchAddButton(sender: AnyObject) {
    
      let randNum = Int(arc4random_uniform(5))
    
      if randNum == 0 {
         timer = NSTimer.scheduledTimerWithTimeInterval(3.0, target: self, selector: #selector(ViewController.changeView), userInfo: ["value": 0], repeats: false)
    
         let n : NSNotification = NSNotification(name: "dummy", object: self, userInfo: ["value": 0])
         NSNotificationCenter.defaultCenter().postNotification(n)
    
    
      }else if(randNum == 1){
        timer = NSTimer.scheduledTimerWithTimeInterval(3.0, target: self, selector: #selector(ViewController.changeView), userInfo: ["value": 1], repeats: false)
    
        let n : NSNotification = NSNotification(name: "dummy", object: self, userInfo: ["value": 1])
        NSNotificationCenter.defaultCenter().postNotification(n)
    
      //〜〜〜省略〜〜〜
    
      }else{
        timer = NSTimer.scheduledTimerWithTimeInterval(3.0, target: self, selector: #selector(ViewController.changeView), userInfo:  ["value": 100], repeats: false)
    
        let n : NSNotification = NSNotification(name: "dummy", object: self, userInfo: ["value": 100])
        NSNotificationCenter.defaultCenter().postNotification(n)
          }
    }
    func changeView() {
        self.performSegueWithIdentifier("toMap", sender: nil)
     }
    }
    
[/code]

SecondViewController.swift

[code]

    import UIKit
    import MapKit
    
    class SecondViewController: UIViewController,MKMapViewDelegate {
    
    @IBOutlet weak var mapView: MKMapView!
    
    
    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(false)
    
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(SecondViewController.start) ,name: "dummy", object: nil)
    
    }
        func start(notification: NSNotification) {
            if let userInfo = notification.userInfo {
                let result = userInfo["value"]! as! Int
    
        switch result {
    
        case 0:
            let coordinate = CLLocationCoordinate2DMake(33.590241, 130.421222)
    
            let span = MKCoordinateSpanMake(0.01, 0.01)
    
            let region = MKCoordinateRegionMake(coordinate, span)
            self.mapView.setRegion(region, animated: true)
    
            let annotation = MKPointAnnotation()
            annotation.coordinate = CLLocationCoordinate2DMake(33.590241, 130.421222)
            annotation.title = "Hakata Station"
            annotation.subtitle = "博多駅"
            self.mapView.addAnnotation(annotation)
    
    
        case 1:
            let coordinate = CLLocationCoordinate2DMake(34.985849, 135.758767)
    
            let span = MKCoordinateSpanMake(0.01, 0.01)
    
            let region = MKCoordinateRegionMake(coordinate, span)
            self.mapView.setRegion(region, animated: true)
    
            let annotation = MKPointAnnotation()
            annotation.coordinate = CLLocationCoordinate2DMake(34.985849, 135.758767)
            annotation.title = "Kyoto Station"
            annotation.subtitle = "京都駅"
            self.mapView.addAnnotation(annotation)
    
        //〜〜〜省略〜〜〜
    
        default:
            let coordinate = CLLocationCoordinate2DMake(43.068661, 141.350755)
    
            let span = MKCoordinateSpanMake(0.01, 0.01)
    
            let region = MKCoordinateRegionMake(coordinate, span)
            self.mapView.setRegion(region, animated: true)
    
            let annotation = MKPointAnnotation()
            annotation.coordinate = CLLocationCoordinate2DMake(43.068661, 141.350755)
            annotation.title = "Sapporo Station"
            annotation.subtitle = "札幌駅"
            self.mapView.addAnnotation(annotation)
          }
         }
        }
       }
    
[/code]


CC BY-SA 3.0
2016-04-14T06:10:25.520
24003
2016-04-15T07:49:37.677
2016-04-15T07:26:29.117
15152
15152
question
ios swift
NSNotification 異なるクラスでの処理を連携させたい


`NSNotification`は、ご質問にあるような画面遷移の際のデータの受け渡しには向いていません。`NSNotificationCenter.defaultCenter().postNotification(n)`で送られた通知は、その時点で該当の通知を受け取るようなobserverが登録されていなければ無視されます。この時点ではまだ画面遷移が始まりもしていないので、`SecondViewController`については、通知を受け取るどころか、インスタンスさえ存在しないでしょう。

* * *

画面遷移時にViewController間でのデータ連携を行いたいのであれば、例えば`prepareForSegue(_:sender:)`メソッドを使うのが簡単です。確実に遷移元と遷移先のインスタンスが生成された状態で呼ばれるので、インスタンスプロパティをデータの受け渡しに使用することができます。

SecondViewController.swift:

[code]

    import UIKit
    import MapKit
    
    class SecondViewController: UIViewController, MKMapViewDelegate {
    
        @IBOutlet weak var mapView: MKMapView!
    
        //`ViewController`から値を受け取るためのプロパティ
        var valueToReceive: Int = 0
    
        override func viewWillAppear(animated: Bool) {
            super.viewWillAppear(false)
    
            //インスタンスプロパティの`valueToReceive`に値が入っているので、それをそのまま使うだけ
            start(valueToReceive)
        }
    
        func start(result: Int) {
            switch result {
            case 0:
                let coordinate = CLLocationCoordinate2DMake(33.590241, 130.421222)
                //以下元のコードと同じ                
            case 1:
                let coordinate = CLLocationCoordinate2DMake(34.985849, 135.758767)
                //以下元のコードと同じ                
    
                //〜〜〜省略〜〜〜
    
            default:
                let coordinate = CLLocationCoordinate2DMake(43.068661, 141.350755)
                //以下元のコードと同じ                
            }
        }
    }
    
[/code]

ViewController.swift:

[code]

    import UIKit
    
    class ViewController: UIViewController {
    
        var timer: NSTimer? //使いもしないインスタンスを生成するのは良くないので修正
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
        }
    
        @IBAction func didTouchAddButton(sender: AnyObject) {
    
            let randNum = Int(arc4random_uniform(5))
    
            if randNum == 0 {
                timer = NSTimer.scheduledTimerWithTimeInterval(3.0, target: self, selector: #selector(ViewController.changeView), userInfo: ["value": 0], repeats: false)
                valueToSend = 0
            } else if randNum == 1 {
                timer = NSTimer.scheduledTimerWithTimeInterval(3.0, target: self, selector: #selector(ViewController.changeView), userInfo: ["value": 1], repeats: false)
                valueToSend = 1
    
                //〜〜〜省略〜〜〜
    
            } else {
                timer = NSTimer.scheduledTimerWithTimeInterval(3.0, target: self, selector: #selector(ViewController.changeView), userInfo:  ["value": 100], repeats: false)
                valueToSend = 100
            }
        }
    
        func changeView() {
            self.performSegueWithIdentifier("toMap", sender: nil)
        }
    
        //`SecondViewController`に渡す値を一時的に保持するためのプロパティ    
        private var valueToSend = 0
    
        // 以下が一番肝心な`prepareForSegue(_:sender:)`
        override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
            if segue.identifier == "toMap" {
                let destinationViewController = segue.destinationViewController as! SecondViewController
                destinationViewController.valueToReceive = valueToSend
            }
        }
    }
    
[/code]

(ところで何のためにボタンを押してから「3秒後に画面遷移」なんて、ユーザをイライラさせるようなことをするのでしょうか?もし、「データ連携がうまくいかないので試しに時間を取ってみた」だけなら、その部分は不要ですから、さらに簡単になります。)

いろいろな理由で上記のコードそのままは使えないかもしれませんが、とりあえず「画面遷移時のデータの受け渡し」としては確実に動くコードになっています。お試しください。


CC BY-SA 3.0
2016-04-14T07:48:23.407
24008
2016-04-15T07:49:37.677
2016-04-15T07:49:37.677
13972
13972
24003
answer