Some terminology first:
Publisher device - device publishing the NSNetService in the local. domain
Browser device - device browsing for service with NSNetServiceBrowser in the local. domain
The issue:
NSNetServiceBrowserDelegate's didRemoveService is not being called on the browser device when both the publisher and the browser device are connected to the same router and thepublisher device goes off the grid by enabling Airplane mode (I think turning WiFi off will also work). When the publisher and the browser are not connected to the router but are communicating directly (peer-to-peer), the issue doesn't reproduce.
The problem is easily reproducible with the Apple's WiTap samplecode application (that is no longer exists in Apple's sample code 😟, but can be found on the net).
Steps to reproduce:
1. Connect the application to the same router
2. Run the WiTap application on both devices
3. Turn airplane mode on publisher device
Result:
The browser device still displays the publisher service
Publisher code
NSNetService *server = [[NSNetService alloc] initWithDomain:@"local." type:@"_myservice._tcp." name:@"my-id" port:0];
server.includesPeerToPeer = YES;
server.delegate = self;
[server publishWithOptions:NSNetServiceNoAutoRename|NSNetServiceListenForConnections];
self.server = server;
Browser code
NSNetServiceBrowser *browser = [[NSNetServiceBrowser alloc] init];
browser.includesPeerToPeer = YES;
browser.delegate = self;
[browser searchForServicesOfType:@"_myservice._tcp." inDomain:@"local."];
self.browser = browser;
Any ideas & suggestions will be highly appreciated!
TL;DR
I suspect that the problem is not directly related to NSNetService but rather related to Bonjour implementation. The reason I think so is that after force closing the browser app and re-running it (while the publisher device is still in Airplane mode), the browser devicestill shows the service as a result of the didFindService delegate method being called for a service that the publisher doesn't publish anymore.
P.S. The issue reproduces on iOS 12 and below (tested down to iOS 7).
Thanks.