2017-01-04 5 views
0

Ich habe einen BaseController (BVC), wo ich angefangen habe, Benachrichtigungen in viewWillAppear & zu hören hören sie auf ViewWillDisappear Methoden.NSNotification für TabBarControllers

BVC 
- CustomView (Notification received updates this VC) 

Jetzt habe ich 4 verschiedene Controller von BVC subclassed.

BVC 
|-- FirstVC (FVC) 
|-- SecondVC (SVC) 
|-- ThirdVC (TVC) 

Nun, ich habe einen TarBarController, die diese drei VCs als seine Einzelteile über einen NavigationViewController (NVC) hat

TabBarController 
|- NVC->FVC 
|- NVC->SVC 
|- NVC->TVC 

Mein Problem ist, ich habe über eine playWillBegin Benachrichtigung von einem Singleton Senden Objekt, das eine AVPlayer-Instanz ist. Die Benachrichtigung wird von der VC empfangen, die oben aktiv ist, aber wenn ich die Tabs nicht schnell umschalte, werden die Benachrichtigungen in den anderen Controllern nicht empfangen.

Ich lese auch in SO, dass andere VC nicht instanziiert sind und das ist der Grund, warum die Benachrichtigungen nicht empfangen werden. Aber ich kann nicht init Methode in VC verwenden, weil seine Frage initWithaCoder verwenden

Mein Projekt ist alles Code und verwendet keine Storyboard usw. So ist meine TabBarController eine schnelle Klasse, hat die Elemente dort und TabBarController-Instanz in AppDelegate

EDIT 1: Relevante SO QA Links Link1 Link2

EDIT 2: um zu klären, warum ich in der Lage, nichts in init hinzufügen() -Methode des VC BaseViewController - Snippet

init() { 
    super.init() //Please refer image for error message 
} 

required init?(coder aDecoder: NSCoder) { 

} 

TabBarController

class TabBarController: UITabBarController, UITabBarControllerDelegate { 

    override func viewDidLoad() { 

     tabBar.tintColor = UIColor.whiteColor() 
     self.delegate = self 

     let FNVC = UINavigationController(rootViewController: FVC()) 
     //Other initialization code 

     let SNVC = UINavigationController(rootViewController: SVC()) 
     //Other initialization code 

     let TNVC = UINavigationController(rootViewController: TVC()) 
     //Other initialization code 
     viewControllers = [FNVC, SNVC, TNVC] 

    } 
} 

enter image description here

Antwort

1

Der erste Grund für die Meldung nicht durch nicht-aktiven tabs empfangen wird, ist, dass unsichtbare Controller unsubscribed sind. Wenn Sie zum Beispiel von Registerkarte 2 (SecondVC) zu Registerkarte 1 (FirstVC) wechseln, wird die -[viewWillDisappear:] für die SecondVC aufgerufen und hört auf zu hören, so dass der Controller keine Benachrichtigungen mehr empfängt.

Ich schlage vor, in -[viewDidLoad:] und stoppen in -[dealloc] (oder deinit in Swift) starten hören:

Obj-C:

- (void) viewDidLoad 
{ 
    [super viewDidLoad]; 
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(someFunction:) name:@"notification_name" object:nil]; 
} 

- (void) dealloc 
{ 
    [[NSNotificationCenter defaultCenter] removeObserver:self]; 
} 

Swift:

override func viewDidLoad() { 
    super.viewDidLoad() 
    NotificationCenter.default.addObserver(self, selector: #selector(BaseController.someFunction), name:Notification.Name("foobar"), object: nil) 
} 

deinit { 
    NotificationCenter.default.removeObserver(self) 
} 

Der zweite Grund ist diese Ansicht m wird noch nicht geladen, daher wird [-viewDidLoad:] nicht aufgerufen und der entsprechende View-Controller ist nicht abonniert. Um dies zu lösen, können Sie die Ansicht von VC erzwingen, wenn Sie View-Controller für Registerkarten erstellen, z.:

Obj-C:

FirstVC *vc1 = [FirstVC new]; 
[vc1 view]; // loading view, subscribing 

Swift:

let vc1 = FirstVC() 
let _ = vc1.view 

UPDATE

Unter der Annahme, dass Sie initializers verwenden können (wie durch @danh in der erklärt Kommentare unten), ist es besser, in der init Methode anstelle von viewDidLoad. In diesem Fall gibt es keine Notwendigkeit Ansicht Laden zu zwingen, und Sie [vc view] Anrufe weglassen:

Obj-C:

- (instancetype) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 
{ 
    if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])){ 
     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notified:) name:@"foobar" object:nil]; 
    } 

    return self; 
} 

Swift:

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { 
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 
    NotificationCenter.default.addObserver(self, selector: #selector(BaseViewController.someFunc), name:Notification.Name("foobar"), object: nil) 
} 
+0

Große Antwort, aber Ihre erste Theorie ist richtig und zweite ist verwirrend. Das OP ist fast sicher falsch, dass die vcs noch nicht zugeordnet sind. – danh

+1

Einfach ausgedrückt, lautet die Antwort: Lassen Sie die vcs Benachrichtigungen für ihren gesamten Lebenszyklus beachten, nicht nur, wenn sie sichtbar sind. – danh

+0

@danh Sie haben Recht - VCs zugewiesen werden sollte, aber es bedeutet nicht, dass ihre Ansichten geladen werden. Letzteres tritt normalerweise auf, wenn der Controller der Registerkarte zum ersten Mal angezeigt wird. – degapps

Verwandte Themen