I have an application that is using the MultiPeer Connectivity framework. Every time the application becomes active in AppDelegate, I make a new MCSession a MCNearbyBrowserService, and a MCNearbyAdvertiserService and call start browsing and start advertising. Then every time the application becomes inactive in AppDelegate, I stop browsing and advertising and set everything to nil. I find that MCNearbyBrowserService causes a crash in its syncQueue:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** - [__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[2]'
*** First throw call stack:
(0x2de3ee8b 0x381396c7 0x2dd7caef 0x2dd7c8b3 0x2f648167 0x2f6493af 0x3861e103 0x38622e77 0x3861ff9b 0x38623751 0x386239d1 0x3874ddff 0x3874dcc4)
libc++abi.dylib: terminating with uncaught exception of type NSException
sometimes when the app reopens.
Here is my code for applicationDidBecomeActive:
self.myIdentifier = [[MCPeerID alloc] initWithDisplayName:[self.class createHash:20]];
self.mainSession = [[MCSession alloc] initWithPeer:self.myIdentifier];
self.mainSession.delegate = self;
peerAdvertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:self.myIdentifier discoveryInfo:nil serviceType: service];
peerAdvertiser.delegate = self;
peerBrowser = [[MCNearbyServiceBrowser alloc] initWithPeer:self.myIdentifier serviceType: service];
peerBrowser.delegate = self;
acceptReset = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(reset) userInfo:nil repeats:YES];
acceptPosts = true;
[peerBrowser startBrowsingForPeers];
[peerAdvertiser startAdvertisingPeer];
self.isBrowsing = true;
and here is my code for applicationWillResignActive:
[acceptReset invalidate];
[peerAdvertiser stopAdvertisingPeer];
[peerBrowser stopBrowsingForPeers];
[self.mainSession disconnect];
self.mainSession = false;
self.isBrowsing = false;
The full code can be viewed here: http://pastebin.com/E3wY6U4N
I remember running into this issue, and the quick fix was to nil out the delegates and release the browser and advertiser. So assuming your App Delegate has a strong property for each the setup method would look like:
self.peerAdvertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:self.myIdentifier discoveryInfo:nil serviceType: service];
self.peerAdvertiser.delegate = self;
self.peerBrowser = [[MCNearbyServiceBrowser alloc] initWithPeer:self.myIdentifier serviceType: service];
self.peerBrowser.delegate = self;
And then when the app enters the background (or otherwise wants to stop browsing/advertising):
self.peerAdvertiser.delegate = nil;
[self.peerAdvertiser stopAdvertisingPeer];
self.peerAdvertiser = nil;
self.peerBrowser.delegate = nil;
[self.peerBrowser stopBrowsingForPeers];
self.peerBrowser = nil;
[self.mainSession disconnect];
I'd also recommend against creating a new MCPeerID
on each app launch, as Multipeer Connectivity has a habit of discovering old peers, and you'll end up discovering your 'former self' on each relaunch.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With