An important part of Bonjour is the ability to browse for services on the network. This article describes how to use the NSNetServiceBrowser class to discover Bonjour network services.
The NSNetServiceBrowser class provides methods for browsing for available Bonjour network services.
Because of the possible delays associated with network traffic, NSNetServiceBrowser objects perform browsing asynchronously by registering with the default run loop. Browsing results are returned to your application through delegate methods. To handle results from an NSNetServiceBrowser object, you must assign it a delegate.
Browsing for Bonjour network services takes three steps:
Initialize an NSNetServiceBrowser instance and assign a delegate to the object.
Begin a search for services of a specific type in a given domain.
Handle search results and other messages sent to the delegate object.
The following sections describe these steps in detail.
To initialize an NSNetServiceBrowser object, use the init
method. This sets up the browser and adds it to the current run loop. If you want to use a run loop other than the current one, use the removeFromRunLoop:forMode:
and scheduleInRunLoop:forMode:
methods.
To begin the browsing process, use the searchForServicesOfType:inDomain:
method.
The service type expresses both the application protocol (FTP, HTTP, and so on.) and the transport protocol (TCP or UDP). The format is as described in Domain Naming Conventions, for example, _printer._tcp
for an LPR printer over TCP.
The domain parameter specifies the DNS domain in which the browser performs its search. Unless you only want to browse a specific domain, pass the empty string (@"") as the domain to allow searchForServicesOfType:inDomain:
to search all domains available to your system. You can retrieve a list of potential browsing domains with NSNetServiceBrowser’s searchForRegistrationDomains
method by passing in the empty string (@""
) for the domain parameter. For more information read through “Browsing for Domains”
To stop a search, use the stop
method. You should perform any necessary cleanup in the netServiceBrowserDidStopSearch:
delegate callback.
Listing 1 demonstrates how to browse for Bonjour network services with NSNetServiceBrowser. The code initializes the object, assigns a delegate, and begins a search for a hypothetical music service type, _music._tcp
, on the local network. Also see the PictureSharingBrowser application in /Developer/Examples/PictureSharingBrowser
for a good example of service browsing.
Note: When the PictureSharingBrowser example code in Mac OS X v10.2 was finalized, the link-local suffix was local.arpa.
, but it changed to local.
before the operating system shipped. Use local.
to specify the link-local network.
Listing 1 Browsing for Bonjour network services
id delegateObject; // Assume this exists. |
NSNetServiceBrowser *serviceBrowser; |
serviceBrowser = [[NSNetServiceBrowser alloc] init]; |
[serviceBrowser setDelegate:delegateObject]; |
[serviceBrowser searchForServicesOfType:@"_music._tcp" inDomain:@""]; |
NSNetServiceBrowser returns all browsing results to its delegate. If you are using the class to browse for services, your delegate object should implement the following methods:
netServiceBrowserWillSearch:
netServiceBrowserDidStopSearch:
netServiceBrowser:didNotSearch:
netServiceBrowser:didFindService:moreComing:
netServiceBrowser:didRemoveService:moreComing:
The netServiceBrowserWillSearch:
method notifies the delegate that a search is commencing. You can use this method to update your user interface to reflect that a search is in progress. When browsing stops, the delegate receives a netServiceBrowserDidStopSearch:
message, where you can perform any necessary cleanup.
If the delegate receives a netServiceBrowser:didNotSearch:
message, it means that the search failed for some reason. You should extract the error information from the dictionary with the NSNetServicesErrorCode
key and handle the error accordingly. See NSNetService for a list of possible errors.
You track services with the netServiceBrowser:didFindService:moreComing:
and netServiceBrowser:didRemoveService:moreComing:
methods, which indicate that a service has become available or has shut down. The “more coming” parameter indicates whether more results are on the way. If this parameter is YES
, you should delay updating any user interface elements until the method is called with a “more coming” parameter of NO
. However, if the parameter returns NO
there is still a chance that more services will become available at a later time. It is important that you make sure to retain the didFindService
parameter before trying to resolve it, or you risk the object becoming deallocated. If you want a list of available services, you need to maintain your own array based on the information provided by delegate methods.
Listing 2 shows the interface for a class that responds to the NSNetServiceBrowser delegate methods required for service browsing, and Listing 3 shows its implementation. You can use this code as a starting point for your service browsing code.
Listing 2 Interface for an NSNetServiceBrowser delegate object (services)
#import <Foundation/Foundation.h> |
@interface NetServiceBrowserDelegate : NSObject |
{ |
// Keeps track of available services |
NSMutableArray *services; |
// Keeps track of search status |
BOOL searching; |
} |
// NSNetServiceBrowser delegate methods for service browsing |
- (void)netServiceBrowserWillSearch:(NSNetServiceBrowser *)browser; |
- (void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)browser; |
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser |
didNotSearch:(NSDictionary *)errorDict; |
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser |
didFindService:(NSNetService *)aNetService |
moreComing:(BOOL)moreComing; |
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser |
didRemoveService:(NSNetService *)aNetService |
moreComing:(BOOL)moreComing; |
// Other methods |
- (void)handleError:(NSNumber *)error; |
- (void)updateUI; |
@end |
Listing 3 Implementation for an NSNetServiceBrowser delegate object (services)
#import "NetServiceBrowserDelegate.h" |
@implementation NetServiceBrowserDelegate |
- (id)init |
{ |
self = [super init]; |
if (self) { |
services = [[NSMutableArray alloc] init]; |
searching = NO; |
} |
return self; |
} |
- (void)dealloc |
{ |
[services release]; |
[super dealloc]; |
} |
// Sent when browsing begins |
- (void)netServiceBrowserWillSearch:(NSNetServiceBrowser *)browser |
{ |
searching = YES; |
[self updateUI]; |
} |
// Sent when browsing stops |
- (void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)browser |
{ |
searching = NO; |
[self updateUI]; |
} |
// Sent if browsing fails |
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser |
didNotSearch:(NSDictionary *)errorDict |
{ |
searching = NO; |
[self handleError:[errorDict objectForKey:NSNetServicesErrorCode]]; |
} |
// Sent when a service appears |
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser |
didFindService:(NSNetService *)aNetService |
moreComing:(BOOL)moreComing |
{ |
[services addObject:aNetService]; |
if(!moreComing) |
{ |
[self updateUI]; |
} |
} |
// Sent when a service disappears |
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser |
didRemoveService:(NSNetService *)aNetService |
moreComing:(BOOL)moreComing |
{ |
[services removeObject:aNetService]; |
if(!moreComing) |
{ |
[self updateUI]; |
} |
} |
// Error handling code |
- (void)handleError:(NSNumber *)error |
{ |
NSLog(@"An error occurred. Error code = %d", [error intValue]); |
// Handle error here |
} |
// UI update code |
- (void)updateUI |
{ |
if(searching) |
{ |
// Update the user interface to indicate searching |
// Also update any UI that lists available services |
} |
else |
{ |
// Update the user interface to indicate not searching |
} |
} |
@end |
Last updated: 2010-03-24