views:

145

answers:

1

When I compile the code below I get the following warning: Incompatible type sending "ITunesFinder *" expected "id"? I am only just starting out and to be truthful am a little confused by this example. I would be interested to know if there is a way to write this example without using the delegate class?

I am also a little confused by the class implementation, the book does not describe what this is based on, or for that matter what Categories, Protocols or Delegates do, nor how they work.

here is the code ...

// INTERFACE
#import <Cocoa/Cocoa.h>
@interface ITunesFinder : NSObject
@end

.

// IMPLEMENTATION
#import "ITunesFinder.h"
@implementation ITunesFinder
-(void) netServiceBrowser: (NSNetServiceBrowser *) b
           didFindService: (NSNetService *) service
               moreComing: (BOOL) moreComing {

    [service resolveWithTimeout:10];
    NSLog(@"Service Found: %@", [service name]);
}

-(void) netServiceBrowser: (NSNetServiceBrowser *) b
         didRemoveService: (NSNetService *) service
               moreComing: (BOOL) moreComing {
    [service resolveWithTimeout:10];
    NSLog(@"Service Lost!: %@", [service name]);
}
@end

.

// MAIN
#import <Foundation/Foundation.h>
#import "ITunesFinder.h"

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    NSNetServiceBrowser *browser = [[NSNetServiceBrowser alloc] init];
    ITunesFinder *finder = [[ITunesFinder alloc] init];

    NSLog(@"iTunesFinder ... Start");
    [browser setDelegate: finder]; // <<< Warning here !!!!
    [browser searchForServicesOfType: @"_daap._tcp" inDomain:@"local."];
    NSLog(@"Browsing ...");

    [[NSRunLoop currentRunLoop] run];

    // Clean up
    [browser release];
    [finder release];
    [pool drain];
    return 0;
}

any pointers / wisdom would be much appreciated.

gary

+4  A: 

When I tried compiling this under 10.6 with gcc 4.2.1, it compiled with the following warning:

main.m:12: warning: class 'ITunesFinder' does not implement the 'NSNetServiceBrowserDelegate' protocol

I suspect this is the same issue you describe, but with a more descriptive diagnostic coming from the compiler (maybe a more recent version than yours?). You can address this warning by adding the protocol to the interface declaration in the header:

@interface ITunesFinder : NSObject<NSNetServiceBrowserDelegate>

The reason the warning was issued is that the setDelegate: method has the following signature:

- (void)setDelegate:(id <NSNetServiceBrowserDelegate>)delegate;

which simply means it can take any object that implements the formal NSNetServiceBrowserDelegate protocol. Since your class interface didn't explicitly declare this, the compiler warns you of the fact. It should still work at runtime, provided the actual methods are provided when the delegate messages are actually sent.

is it possible to write this example without using the delegate class?

No, the delegate class is the way you receive event notifications.

I am also a little confused by the class implementation, the book does not describe what this is based on, or for that matter what Categories, Protocols or Delegates do, nor how they work.

The NSNetServiceBrowserDelegate protocol defines a set of methods that your class needs to implement. You can think of it just like an interface in Java or a virtual base class in C++. The difference in Objective-C (which doesn't support multiple inheritance) is that you don't inherit from the interface you are trying to implement, you merely declare the fact that your particular class implements these methods according to the protocol.

Now protocols are used for a variety of things, and a very common pattern in Cocoa is to use them for callbacks. So here, your ITunesFinder is implementing the browser protocol in a way such that the NSNetServiceBrowser knows how to call your class (which it has never seen before!) in order to provide browser notifications.

These delegates are often used to delegate behaviour from a framework class to one of your classes, to allow you to easily customise things without lots of subclassing, and to receive notifications of events (typically before and after something interesting). It's a very elegant model.

The Apple documentation is very good on this subject:

gavinb
Hi Gavin, I was actually compiling under Clang LLVM 1.0 to get that error, swapping to GCC 4.2 gives me the same error that you got.
fuzzygoat
Thanks again Gavin, I updated the interface to ... @interface ITunesFinder : NSObject <NSNetServiceBrowserDelegate> @end and the error goes away. Thank you again for your comments, I am in that area where you know a little (but not all the concepts). I will check out the documentation you linked.
fuzzygoat
@fuzzygoat No problem, have fun! :)
gavinb