Bonjour service browsers and publishers that want to support hierarchical domain browsing should search for domains. If your application searches for services but does not care which domain it originates from, or, if your application publishes services and does not need to only publish to specific domains, you do not need to browse for domains. This article explains how to use the NSNetServiceBrowser class to discover available domains.
The NSNetServiceBrowser class provides methods for browsing available domains. You should use these methods if you are writing a browser application that needs to see services outside the local network, or if you are publishing a service that needs to be seen outside the local network.
If you are writing a Bonjour network service browser, in general you should provide your users with the ability to browse all the domains available to them.
If the source domain of a service is not important, pass the empty string (@"") into the NSNetService and NSNetServiceBrowser methods that take a domain to find services. By passing the empty string for the domain, the system will automatically search the default domains as determined by the system's configuration and the network environment. In Mac OS X version 10.4, this means the local domain and possibly other global domains, whereas in Mac OS X version 10.2 and 10.3, this limits the search to the local. domain. Also, passing the empty string in domain searches will ensure that your application will be able to take advantage of future enhancements made to Bonjour. If you want to limit the domain which is searched in for services, just pass the name of the domain (such as local.) as the domain parameter.
Because domain browsing can take time, NSNetServiceBrowser objects perform browsing asynchronously by registering with a run loop. Browsing results are returned to your application through delegate methods. To correctly use an NSNetServiceBrowser object, you must assign it a delegate.
Browsing for domains takes three steps:
Initialize an NSNetServiceBrowser instance and assign a delegate to the object.
Begin a search for domains (either for registration or for browsing).
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.
If you want to search for domains in which you can register services, use the searchForRegistrationDomains method. If you want to find all domains available for browsing, use the searchForBrowseDomains method.
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 registration domains with NSNetServiceBrowser. The code initializes the object, assigns a delegate, and begins a search for available domains.
Listing 1 Browsing for registration domains
id delegateObject; // Assume this exists. |
NSNetServiceBrowser *domainBrowser; |
domainBrowser = [[NSNetServiceBrowser alloc] init]; |
[domainBrowser setDelegate:delegateObject]; |
[domainBrowser searchForRegistrationDomains]; |
NSNetServiceBrowser returns all browsing results to its delegate. If you are using the class to browse for domains, your delegate object should implement the following methods:
netServiceBrowserWillSearch:
netServiceBrowserDidStopSearch:
netServiceBrowser:didNotSearch:
netServiceBrowser:didFindDomain:moreComing:
netServiceBrowser:didRemoveDomain: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 NSNetServicesError for a list of possible errors.
You track domains with the netServiceBrowser:didFindDomain:moreComing: and netServiceBrowser:didRemoveDomain: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 not update any user interface elements until the method is called with a “more coming” parameter of NO. However, just because the parameter is NO, does not mean that more services will not become available in the future. If you want a list of available domains, 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 domain browsing, and Listing 3 shows its implementation. You can use this code as a starting point for your domain browsing code.
Listing 2 Interface for an NSNetServiceBrowser delegate object (domains)
#import <Foundation/Foundation.h> |
@interface NetServiceDomainBrowserDelegate : NSObject |
{ |
// Keeps track of available domains |
NSMutableArray *domains; |
// Keeps track of search status |
BOOL searching; |
} |
// NSNetServiceBrowser delegate methods for domain browsing |
- (void)netServiceBrowserWillSearch:(NSNetServiceBrowser *)browser; |
- (void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)browser; |
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser |
didNotSearch:(NSDictionary *)errorDict; |
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser |
didFindDomain:(NSString *)domainString |
moreComing:(BOOL)moreComing; |
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser |
didRemoveDomain:(NSString *)domainString |
moreComing:(BOOL)moreComing; |
// Other methods |
- (void)handleError:(NSNumber *)error; |
- (void)updateUI; |
@end |
Listing 3 Implementation for an NSNetServiceBrowser delegate object (domains)
#import "NetServiceDomainBrowserDelegate.h" |
@implementation NetServiceDomainBrowserDelegate |
- (id)init |
{ |
self = [super init]; |
domains = [[NSMutableArray alloc] init]; |
searching = NO; |
return self; |
} |
- (void)dealloc |
{ |
[domains 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 domain appears |
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser |
didFindDomain:(NSString *)domainString |
moreComing:(BOOL)moreComing |
{ |
[domains addObject:domainString]; |
if(!moreComing) |
{ |
[self updateUI]; |
} |
} |
// Sent when a domain disappears |
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser |
didRemoveDomain:(NSString *)domainString |
moreComing:(BOOL)moreComing |
{ |
[domains removeObject:domainString]; |
if(!moreComing) |
{ |
[self updateUI]; |
} |
} |
// Error handling code |
- (void)handleError:(NSNumber *)error |
{ |
NSLog(@"An error occurred. Error code = %@", error); |
// Handle error here |
} |
// UI update code |
- (void)updateUI |
{ |
if(searching) |
{ |
// Update the user interface to indicate searching |
// Also update any UI that lists available domains |
} |
else |
{ |
// Update the user interface to indicate not searching |
} |
} |
@end |
Last updated: 2009-10-09