lulusen
lulusen

Reputation: 45

How to dismiss other Alert Controller and present a new Alert Controller immediately without delay

I am currently having problems with delay of presenting a new alert controller after dismissing another alert controller.

My situation is as below:

There are two roles for peer to peer connection using MPC: Master and Slave.

Ideal case: only one master available

However, each device can set as Master when there is no connection between devices.

When both master devices are connected, there would be a conflict to the ideal case.

Therefore, I want to make an election of Master.

When two devices which are both Master individually are now in connection, then alert controller of Master election will prompt in each device. When one of the device tabs "Stay As Master" button first, then another device will dismiss election Alert Controller and prompt "xxx remains as master" alert.
However, I discover that there is delay of dismissing the previous Alert Controller.

Codes in MainVC:

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(testing), name: NSNotification.Name(rawValue: "hasMaster"), object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(stayAsMaster), name: NSNotification.Name(rawValue: "StayAsMaster"), object: nil)

}

func testing(notification: Notification){
    if(appDelegate.mpcHandler.checkNoOfPeersConnected()>0){
        if self.appDelegate.masterSlaveDataController.checkHasMaster() && self.appDelegate.masterSlaveDataController.checkMaster(){
            self.promptHasMaster()
        }
        else{
            DispatchQueue.main.asyncAfter(deadline: .now()){
                if self.appDelegate.masterSlaveDataController.checkHasMaster() && self.appDelegate.masterSlaveDataController.checkMaster(){
                    self.promptHasMaster()
                }
            }
        }
    }
}

func promptHasMaster(){//prompt Elect Master Alert Controller
    let alertController = UIAlertController(title: "Elect Master", message: "There are more than one masters in the connection. One of you has to give up the master role and switch to slave!", preferredStyle: .alert)
    let peerID = self.appDelegate.mpcHandler.session.myPeerID
    let m = UIAlertAction(title: "Stay as Master", style: .default, handler: { (alert) in
        self.appDelegate.mpcHandler.send(d: self.mToDictionary(peerID: peerID, action: "stayAsMaster")!)
        })
    let s = UIAlertAction(title: "Switch to Slave", style: .default, handler: { (alert) in
        self.appDelegate.mpcHandler.send(d: self.mToDictionary(peerID: peerID, action: "switchToSlave")!)
        })
    alertController.addAction(m)
    alertController.addAction(s)
    self.present(alertController, animated: true, completion: nil)

}

//Create NSDictionary for sending peerID
func mToDictionary(peerID: MCPeerID, action: String) -> [NSDictionary]?{
    var dict: [NSDictionary] = [["action" : action]]
    let d = ["peerID" : peerID] as NSDictionary
    dict.append(d)
    return dict
}

func stayAsMaster(notification: Notification){
    let peerId = NSDictionary(dictionary: notification.userInfo!)
    print("stay as master", peerId.allValues)
    if presentedViewController == nil {
        let alertController = UIAlertController(title:  String(describing: peerId.allValues) + " remains as Master", message: "", preferredStyle: .alert)
        let dismiss = UIAlertAction(title: "Dismiss", style: .destructive, handler: nil)
        alertController.addAction(dismiss)
        self.present(alertController, animated: true, completion: nil)
    } else{
        let alertController = UIAlertController(title:  String(describing: peerId.allValues) + " remains as Master", message: "", preferredStyle: .alert)
        let dismiss = UIAlertAction(title: "Dismiss", style: .destructive, handler: nil)
        alertController.addAction(dismiss)
        self.dismiss(animated: false) { () -> Void in
            self.present(alertController, animated: true, completion: nil)

        }
    }

}

Codes in MPCHandler:

func send(d: [NSDictionary]){
    NSLog("%@", "Send data: \(d) to \(session.connectedPeers.count) peers")

    if session.connectedPeers.count > 0{
        do {
            let data = NSKeyedArchiver.archivedData(withRootObject: d)
            try self.session.send(data, toPeers: session.connectedPeers, with: .reliable)
        } catch {
            NSLog("%@", "Error for sending data: \(error)")
        }
    }
}

func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
    NSLog("%@", "didReceive: \(data)")
    if var dict: [NSDictionary] = NSKeyedUnarchiver.unarchiveObject(with: data) as? [NSDictionary]{
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        let d = dict.removeFirst()
        switch d.value(forKey: "action") as! String {
        case "stayAsMaster":
            NotificationCenter.default.post(name: NSNotification.Name(rawValue: "StayAsMaster"), object: nil, userInfo: [peerID:dict.first!])
        default: break
        }
    }
}

When I tab "Stay as Master" in the Alert Controller of one device, the console of Xcode of another device prints the print("stay as master", peerId.allValues) immediately, but it dismisses the current alert controller after several seconds.

Does anyone have any idea, please? Thanks for any help in advance.

Upvotes: 1

Views: 579

Answers (1)

mugx
mugx

Reputation: 10105

I see a couple of potential issues in your code, try to change these:

  • whenever you post a notification wrap such code inside a DispatchQueue.main.async

    DispatchQueue.main.async {
      NotificationCenter.default.post(name: NSNotification.Name(rawValue: "StayAsMaster"), object: nil, userInfo: [peerID:dict.first!])
    }
    

    please check here: Posting NSNotification on the main thread

  • please add removeObserver (or you might crash after deinit):

    deinit {
      NotificationCenter.default.removeObserver(self)
    }
    

Upvotes: 1

Related Questions