Update both sides of a UISplitView Controller

I asked this question over on Stack Overflow and based on the answers I have recieved what I want to do should be possible however I am still leaning towards it can not be done.


I have a NSTimer updating several views via a delegate on a set timeframe.

I thought it would look nice to place my views into a split view on an iPad as well as the iPhone 6x Plus. I successfully moved my views into a split view controller however when I rotate the device only one side is updated via the delegate (master is updated or detail is updated) depending on where I was in the app when I rotate the device from portrait. That side continues to Update while the device is in the "Split View Mode". If I click on a new row in the master and the master was updating (detail was not) then the detail starts updating and the master stops.


I have a MasterTimer class that is instantiated once and only once when the app is launched or returns to the foreground that has several delegate methods (protocol). This masterTimer class has an instance of a NSTimer that is firing updates to additional Items. When the Timer fires it notifies through the delegate that something has changed and that the views should be updated. My views are registered to listen for the delegate. When the device is in portrait mode, the views and the app are working as one would think. It breaks apart when the views are in a split view.


I have a hunch based on the fact that it works as advertised that I acctually cant update both sides of a split view when both the master and the detail are on screen. Is this the case? If it is not what am I doing wrong.


Here is some sample code that hopefully explains what I am doing:


MasterTimer:


import UIKit
protocol MasterTimerDelegate {
    func masterTimerDidUpdate(item: Item, forGroup group: Group)
    func masterTimerDidUpdateAllItems()
    func masterTimerDidUpdateProgressForItem(item: Item, forGroup group: Group, withProgressCompleted progress: Double)

}
class MasterTimer: NSObject {
     //...... (stuff here)
     func ticToc() { // called by the NSTimer
          //do stuff
          delegate?.masterTimerDidUpdate(item, forGroup: group)
          delegate?.masterTimerDidUpdateAllItems()
          delegate?.masterTimerDidUpdateProgressForItem(item, forGroup: group, withProgressCompleted: item.progressDuration)
  
     }
}


AllGroupsView: What should be the MasterView in the SplitView on landsscape


class AllGroupsViewController: UITableViewController, GroupDetailViewControllerDelegate, UINavigationControllerDelegate, MasterTimerDelegate {

override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        // do stuff
        tableView.reloadData()
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "reloadList:", name: "reloadList", object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "didRotate:", name: UIDeviceOrientationDidChangeNotification, object: nil)
    }
  
    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        navigationController?.delegate = self
        masterTimer.delegate = self
       // do stuff
    }
  
    func reloadList(notification: NSNotification) {
        if (self.tableView != nil) {
            // do stuff
            self.tableView.reloadData()
        }
    }
  
    func didRotate(notification: NSNotification) {
        if (self.tableView != nil) {
            // do stuff
            // trying to reset the delegate on rotation thinking that this would help. It does not
            masterTimer.delegate = self
            self.tableView.reloadData()
        }
    }

     //do a bunch of stuff
     // Start of delegate implementation
    func masterTimerDidUpdate(item: Item, forGroup group: Group) {
          // I dont care about this one in this view. Will make optional when I do some cleanup but is currently required
    }

    func masterTimerDidUpdateAllItems() {
        for group in groups {
            if let cell = self.tableView.cellForRowAtIndexPath(NSIndexPath(forRow: groups.indexOf(group)!, inSection: 0)) as? GroupCell {
                configureLabelsForCell(cell, forGroup: group)
                cell.progressCirclesForGroupView.updateGroupProgressCircles(group)
            }
        }
    }

    func masterTimerDidUpdateProgressForItem(item: Item, forGroup group: Group, withProgressCompleted progress: Double) {
       // I dont care about this one in this view. Will make optional when I do some cleanup but is currently required
    }
}


For brevity the GroupViewController is similar to the code above. Trust me they are both working correctly when in portrait and they were working before I tried to add in the split view for the iPad and the iPhone 6x Plus.


Again the answers I have recieved on stack overflow lead me to believe that there should be no reason that I can't update both the master and the detail view in landscape mode. The only thing I can think of why this is not working for me is that If I rotate the device from what will be the master view that it is the only one that is technically on the main queue and that the detail view is drawn and then released, and vice versa. I could be wrong as I am new to iOS but not other languages and platforms where something like this is doable.


Any tips or answers are much appreciated.

So after doing some hunting and asking around on other forums It appears that my MasterTimer object that is broadcasting a message to anyone that will listen that something changed can only broadcast to one listeneing object at a time. At least that is how it was explained on how delegates work. I admit this seems odd to me but am willing to take it as is and work around it.


That being the case how would I go about updating both sides of the splitview?


should I subclass the UISplitview controller and have it subscribe to the MasterTimer delegate and then figure out a way to let it update the children views?


Or


Should I figure out a way to set up an NSNotificationCenter.defaultCenter().addObserver type call?


Is there a specific broadcast type messge that goes to the whole stack and if the object knows what to do with the message it does something within the iOS platform. C++ has one so I would assume swift and iOS does I just cant figure out what it is. I thought it was setting up a protocol and having something implement that protocol (i am listening to the change and know what to do with it if you tell me).

You're right that the delegate pattern is not appropriate if there is more than one object that needs to be informed of a change. Your singleton has only one "delegate" property and it can only have one value at a time. So any message you send to the delegate will only be delivered to that one object, whoever most recently was set as the delegate.


You could change your interface to keep a variable number of objects (add/remove methods instead of get/set) in a mutable array in your singleton. Or you could add a second delegate property with a different name and call both delegates. But the simpler and more general solution is to just use the NSNotification approach.

Message is kind of old, but..... Send a message to the master view then after the update is done, have the master view send a message to the detail view.

Update both sides of a UISplitView Controller
 
 
Q