2017-01-20 8 views
2

私は2つの迅速なクラスを持っていて、1つは、他のクラスのメソッドを参照する必要があります。それぞれのビューコントローラの両方がtabBarControllerに添付されているので、私は、このようなのようなインスタンスを作成してみました:MapVCは、私が呼び出したいメソッドを保持している異なるSwiftクラスからメソッドを呼び出そうとしています

let mapVC : MapVC = self.tabBarController!.viewControllers![1] as! MapVC 
mapVC.loadViewIfNeeded() 
mapVC.add(newLocation:location_one) // .add is the method I want to call 

を。そして、はtabBarの2番目のオプションです。したがって、インデックスは1です。ただし、オブジェクトmapVCをキャストするとエラー[fatal error: unexpectedly found nil while unwrapping an Optional value]が表示されます。問題はインスタンスmapVCを作成することと関係していると私は信じていますが、私はそれを正しく設定していないかもしれないと信じていますが、それを修正する方法がわかりません。

私の問題をどのようにフレーズするかはまだ分かりません。まだ混乱している場合は、コメントに詳細を記入することができます。

答えて

3

私は通常、各タブの代理人としてカスタムtabBarControllerでこれを行いますが、私はスタック内のviewControllersにアクセスするあなたの方法がとても好きです。あなたのバージョンに何が間違っているのかを見てみましょう。

これはいただきました!あなたのコードでアップ私たちは、デバッグに役立つかもしれない。この

if let tC = self.tabBarController { 
    if let vcs = tC.viewControllers { 
     if let map = vcs[1] as? MapVC { 
      print("map vc found in stack") 
      map.loadViewIfNeeded() 
      map.add(newLocation:location_one) 
     } else { 
      print("no map vc found at index 1") 
     } 
    } else { 
     print("no stack found") 
    } 
} else { 
    print("no tab bar found") 
} 

ようにそれを実行してみてください、あなたはそれがnilを返しているmapVCだと確信していますか?


編集:あなたはコメントで説明したように、あなたが離れてtabBarControllerからsegueingされている場合、新たに提示のViewControllerのtabBarControllerプロパティがApple Docsごとのようにゼロになります。

このプロパティは、ビューコントローラがタブバーコントローラ内に埋め込まれていない場合はnilです。

一つの解決策は、この図の通りvc2からvc3tabBarControllerの参照を渡すことであろう。

[tabBarController] 
    |  | 
    [vc1] [vc2] - both have a reference to tabBarController 
      | 
      [vc3] - no reference yet 

セットアップvc3は、タブバーの参照 を保持する - それは、既存のtabBarControllerプロパティを使用するのではなく、このための新たなVARを作成するために、おそらく最高です。

class vc3:UIViewController { 

    var tabBarReference:UITabBarController? 

    func addALocation(location:CLLocationCoordinate2D) { 
     if let tbc = self.tabBarReference { 
      if let map = tbc.viewControllers[1] as? MapVC { 
       map.loadViewIfNeeded() 
       map.add(newLocation:location) 
      } 
     } 
    } 

} 

そしてvc2内部vc3にアクセスし、それが提示される前に参照を与えるためにセグエ方法の準備使用。

class vc2:UIViewController { 

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 
     if let vc3 = segue.destinationViewController as? vc3 
      vc3.tabBarReference = self.tabBarController 
     } 
    } 

    func goToVC3() { 
     self.performSegueWithIdentifier("goToVC3", sender: nil) 
    } 

} 

私はこのコードをテストしていませんが、それは私はあなたが乗る方法を知ってみましょう、理論的には動作するはずです。

+0

私はこれを私のコードに実装し、 "タブバーが見つかりません"を返しました。これは私が問題だと思ったものですが、私のビューコントローラはtabBarControllerで構造化されているので、むしろ奇妙です。何が起きているか知っていますか? – Kevin

+0

@ KevinどのようにタブバーにviewControllerを追加していますか? – Wez

+0

私がtabBarを設定する方法は、もともとデフォルト(2つのタブ)を使用してから、3番目のView ControllerにセグメントしたtabBarItemを最後に追加しました。これはあなたの質問に答えますか?もっと情報が必要な場合は、私はそれを提供して喜んで! – Kevin

0

これを実現する2つの方法は、委任または通知によるものです。あなたのケースでは、私はあなたが通知を見て、add(newLocation:)の通知の機能を呼び出す必要がありますと思う。

以下は、あるクラスが別のクラスで関数を呼び出す簡単な例です。あなたはこれを遊び場に投げ込んで、どのように動作するか見ることができます。

ビューコントローラでは、一般にviewDidLoadのイベントの監視を開始しますが、クラスをどのように構造化したかによって、他の場所が適している可能性があります。

class MapVC { 

    init() { 
     print("Adding self as observer now...") 
     NotificationCenter.default.addObserver(self, selector: #selector(add), name: NSNotification.Name.init("addNewLocation"), object: nil) 
    } 

    @objc func add(notification: Notification) { 
     guard let location = notification.object as? CLLocation else { 
      return print("Did not recieve a CLLocation object in notification") 
     } 
     print("Got location with lat: \(location.coordinate.latitude), and lon:\(location.coordinate.longitude)") 
     // your code for handling the addition of a new location 
    } 
} 

class OtherVC { 
    func add() { // however you're calling this function... you might be passing in a location here, but for demonstration, just creating a new one 
     let location = CLLocation(latitude: 100, longitude: 100) 
     NotificationCenter.default.post(name:  NSNotification.Name.init("addNewLocation"), object: location) 
    } 
} 


let mapVC = MapVC() 
let otherVC = OtherVC() 

otherVC.add() 
+0

通知の内容とこれをどのように実装することができるかをさらに説明できますか? – Kevin

+0

@Kevin私はあなたがテストするために遊び場に投げることができる例を含めるように私の応答を編集しました。 –

+0

私は通知を通して情報を渡すこのコンセプトが好きです。あなたのコードはプレイグラウンドで動作していますが、これをファイルに実装しようとするとエラーが発生します(必要なイニシャライザinit(コーダ)はUIViewControllerのサブクラスで提供する必要があります)。実装は遊び場と比べて異なっていますか? – Kevin

0

これは、NotificationCenterを使用して行うことができます。 通知を受け取るクラスに通知リスナーを登録し、処理を行う必要があります。そして、あなたは他のクラスからの通知を投稿する必要があります。

一般に、受け取るクラスのviewDidLoad()に通知を登録する必要があります。

1

私は...あなたのビューコントローラは次のように存在している場合、私がチェックします...そして、

extension Collection where Indices.Iterator.Element == Index { 

    /// Returns the element at the specified index iff it is within bounds, otherwise nil. 
    subscript (safe index: Index) -> Generator.Element? { 
     return indices.contains(index) ? self[index] : nil 
    } 
} 

...最初のプロジェクトに

guard let mapVC : MapVC = self.tabBarController?.viewControllers?[safe: 1] as? MapVC else { 
    print("could not find mapVC") 
    return 
} 
mapVC.loadViewIfNeeded() 
mapVC.add(newLocation:location_one) 

チャンスをこのセーフ配列の拡張子を追加しますおそらくこのメソッドをあまりにも早く呼び出しているということです。タブバーやコントローラーのようなサウンドはロードされません。最後の手段として、viewWillAppearまたはviewDidAppearを呼び出してみてください。

関連する問題