Warning in ITunesFinder example (Apress - Learning Obj-C) - objective-c

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

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:
Basics of Protocols
Objective-C Protocols
Cocoa delegates

Related

Subclass Objective-C class without linking with the superclass?

I'm writing a SIMBL plugin for Spotlight, and I'm trying to create a subclass of an internal Spotlight type. While I can get headers directly from the executable using class-dump, I don't have a static library to link against, so compiling a subclass of one of those internal classes fails (even though the classes will be available at runtime). I've been following Mike Ash's instructions on subclassing classes at runtime, but it's pretty inconvenient. Is there any way to create a subclass of an Objective-C class without the superclass being available at link time?
This is entirely possible, and not actually very difficult to do. Here's a simple example with NSValue:
#interface MySubclass : NSObject
-(void) someMethod;
#end
#implementation MySubclass
+(void) load {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
class_setSuperclass(self, NSClassFromString(#"NSValue"));
#pragma clang diagnostic pop
}
-(void) someMethod {
NSLog(#"%#", [self superclass]);
}
-(const char *) objCType {
return #encode(int);
}
-(void) getValue:(void *)value {
if (value) {
*((int *) value) = 10;
}
}
#end
int main() {
MySubclass *theSubclass = [MySubclass new];
[theSubclass someMethod];
NSLog(#"%i", [theSubclass isKindOfClass:[NSValue class]]);
}
class_setSuperclass, while deprecated, still has an implementation as of OS X 10.10, and can be done after the class has been registered. I have not fully explored the effects of changing a class's superclass post the creation of an instance of that class, however, so take caution if you are to do this at any point past +load or +initialize.
This may make it difficult to call methods on super, but this could be gotten around by simply declaring a category on NSObject (or whichever superclass you choose to inherit from in your implementation).

Can NSUUID be extended by inheritance? How?

Recently (reviewing some code) I stumbled upon an oddity that results in a bug in our program.
An API we are using has the following implementation (that I am going to write in Swift, even though the original code is in Objective-C)
internal class MyUUID: NSUUID { }
Which is completely useless as it always returns an empty instance.
I am going to paste the code from my playground here for explanation purposes.
For example: creating a simple NSUUID would be something like this:
let a = NSUUID()
a.description //this creates a valid uuid
While creating a MyUUID should be similar
let b = MyUUID()
b.description //it returns an instance, but is completely empty.
But it doesn't work.
Inspecting a little bit more, reveals the NSUUID initialiser creates a __NSConcreteUUID instance, while MyUUID doesn't and it doesn't matter what I try to do, it won't create an appropriate UUID.
So, my question: Is it possible to be able to create a child implementation of NSUUID?
Your evidence would appear empirically to answer your own question: it's not possible. NSUUID would appear to be a class cluster rather than a single class, which effectively prevents subclassing.
An alternative idea to Aaron's:
Implement an object that has an NSUUID rather than that is one. Implement -forwardingTargetForSelector: and return your instance of NSUUID. Consider overriding -isKindOfClass:, but ideally don't unless you have to. Then you should be able to pass your class as though it were an NSUUID to anyone that expects one without their knowing the difference.
Given that the solution depends upon the fallback mechanism built into dynamic messaging, I suspect there's no Swift equivalent; however if you define your class as Objective-C then it should be equally usable from Swift.
You could use class_setSuperclass to change the superclass of MyUUID at runtime. This approach would be illegal in Swift, due to type safety, but you could still do it in Objective-C.
Depending on your actual goals you may be able to use CFUUIDRef instead.
As requested, here's an example of the class_setSuperclass approach. Just drop this in to a new single view project.
#import <objc/runtime.h>
#interface MyUUID : NSUUID
- (void) UUIDWithHello;
#end
#implementation MyUUID
- (void) UUIDWithHello {
NSLog(#"Hello! %#", self.UUIDString);
}
#end
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Make a UUID that you want to subclass
NSUUID *uuid = [[NSUUID alloc] init];
NSLog(#"Initial UUID: %#", uuid.UUIDString);
// Ignore deprecation warnings, since class_setSuperclass is deprecated
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
// Change MyUUID to inherit from the NSUUID's hidden subclass instead of NSUUID
class_setSuperclass([MyUUID class], [uuid class]); // [uuid class] is __NSConcreteUUID
// Turn deprecation warnings back on
#pragma GCC diagnostic pop
// Make a new myUUID and print it
MyUUID *myUuid = [[MyUUID alloc] init];
[myUuid UUIDWithHello];
}
#end
Note that this is a bit dangerous. If whatever secret subclass NSUUID has additional instance variables, it will require more memory, which [MyUUID alloc] won't request. This could cause a crash later when something requests these instance variables.
To get around this, you could instead instantiate your MyUUID instance like this:
NSLog(#"Initial UUID's class: %#", NSStringFromClass(uuid.class));
Class topSecretUUIDSubclass = uuid.class; // __NSConcreteUUID
MyUUID *myUuid2 = [[topSecretUUIDSubclass alloc] init];
[myUuid2 UUIDWithHello];
object_setClass(myUuid2, [MyUUID class]);
Basically this will make myUuid2 a __NSConcreteUUID and then change it to a MyUUID. However, this will only work if MyUUID doesn't add any instance variables.
If MyUUID does need to add its own instance variables, it will need to override +alloc to provide additional memory for these instance variables, using class_createInstance().

Release method not recognized at runtime (non Cocoa)

I'm a newbie to Objective-C but have extensive experience in C and C++. The first thing I have noticed is that there is a real void in basic tutorials out there as all assume you are developing for the iPhone or Mac and using Cocoa. I'm not using Cocoa or Gnustep. To the point:
As a simple example to get started I'm trying to wrap the C's File I/O functionality. My code starts as
File.h
#include <objc/Object.h>
#include <stdio.h>
#interface File:Object
{
FILE *pFile;
char *path;
}
#property FILE *pFile;
#property char *path;
- (void)new;
- (void)OpenReadText:(const char*)var1;
- (void)release;
#end
And File.m
#include "File.h"
#implementation File
#synthesize pFile, path;
- (void)new
{
self = [super init];
}
- (void)release
{
fclose(pFile);
[super release];
}
- (void)OpenReadText:(char*)var1
{
path = var1;
pFile = fopen(path,"r");
}
#end
Then main.m
#include <stdio.h>
#import <objc/Object.h>
#include "File.h"
int main(void) {
File *Fileobj = [File new];
[Fileobj OpenReadText:"File.h"];
[Fileobj release];
}
The compiler gives me a warning that my object "may not respond to '-release'". Then when running the program is results in a runtime error: "does not recognize release. This application has requested the Runtime to terminate" .. and so on.
I'm guessing I'm making a simple newbie error, but where? Or perhaps there is something missing? I'm hoping someone can point me in the right direction here. Thanks.
If this qst has been asked already then a reference would do too. I did try to find a reference but no luck.
FOLLOW UP:
changed release method to
- (void)release
{
fclose(pFile);
[super free];
}
and it appeared to work. Apparently free is recognized in object.h.
As others have said it is unusual to use Objective-C without the Foundation frameworks. However, the Object class should implement release, retain etc. The Object class included (but not used) in Apple's Objective-C Runtime certainly contains these basic methods.
Assuming your Object class does contain these basic methods there are a couple of problems with your class as implemented.
First, you have created a new instance method which simply calls [super init]. The new method by convention is a class method which is shorthand for calling alloc and init to create and initialise an object. new is defined in Apple's Object class. It is implemented as:
+ (id)new
{
id newObject = (*_alloc)((Class)self, 0);
Class metaClass = self->isa;
if (class_getVersion(metaClass) > 1)
return [newObject init];
else
return newObject;
}
Note that this method is a class method, signified by the + instead of the -. GNUStep implements new as follows:
+ new
{
return [[self alloc] init];
}
The idiomatic way to use new would be:
File *obj = [File new];
This is in fact what you have done, however, this is calling the class method new not your instance method new.
If you wanted to call your new method you'd have to call:
File *obj = [[File alloc] new];
but as others have stated you'd need to return your object. Removing your new method would have no effect on your implementation as it isn't currently being called.
Secondly, you have placed your call to fclose in your overriden release method. This is wrong, certainly in Apple's implementation of Object anyway, GNUstep appears to be different. release could get called multiple times on a single instance of an object. retain and release are used to increment/decrement the objects retain count. Only when the retain count reaches zero should the file handle be closed. Normally, within Foundation you'd place the call to fclose in a dealloc method. dealloc is Objective-C's destructor method. The dealloc should look something like:
- (void)dealloc
{
fclose(pFile);
[super dealloc];
}
However, dealloc doesn't appear to be implemented in either Apple's or GNUstep's Object class. There is, as you point out in your question a free method which seems to be a destructor.
It would appear that replacing the above dealloc method with an equivalent free method would work as a destructor, e.g.:
- (void)free
{
fclose(pFile);
[super free];
}
Apple's implementation of Object contains retain and release methods but the GNUstep implementation does not. Neither implementation contains a dealloc method.
The implementations of Object.m and NSObject.m for Apple and GNUstep can be found at the following locations:
Apple Object.m: http://opensource.apple.com/source/objc4/objc4-532.2/runtime/Object.m
GNUstep Object.m: https://github.com/gnustep/gnustep-libobjc/blob/master/Object.m
Apple NSObject.mm: http://opensource.apple.com/source/objc4/objc4-532.2/runtime/NSObject.mm
GNUstep NSObject.m: https://github.com/gnustep/gnustep-base/blob/master/Source/NSObject.m
Is release defined on class Object? If it is not, then your call to
[super release];
will not work. (In cocoa, release is a member of NSObject; your Object class may or may not have it, and in fact the retain/release reference counting might not be there at all.)
You should confirm that your base class includes all methods called via super.
As #xlc0212 pointed out, the reference counting style of memory management is included in NSObject.
NSObject is a part of CoreFoundation library for Cocoa, CocoaTouch and GnuStep. I would say you need to link to CoreFoundation.
One book that I've read and focuses on pure Objective-C (not necessarily Cocoa) is "Programming in Objective-C 2.0" by Steven G Kochan.

Threading in Objective C

I am new to Objective-C and i was trying out a sample program in Threads from the book "Learn Objective-C for java developers".
I am getting 6 errors on the function definition.
Its with errors.
Is there any link that gives good threading example for beginners like me.
Thread2.m
#import <Foundation/Foundation.h>
#import "Process.h"
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Process* process = [Process new];
NSProgressIndicator* indicator = [NSProgressIndicator new];
Heartbeat* heartbeat = [Heartbeat startHeartbeatProcess:process withIndicator:indicator];
[heartbeat stop];
[pool drain];
return 0;
}
Process.h
#import <Foundation/Foundation.h>
#interface Process : NSObject {
}
#property double progress;
#end
#interface NSProgressIndicator : NSObject {
}
#end
#interface Heartbeat : NSObject {
#public
NSThread* thread;
NSProgressIndicator* indicator;
Process* monitor;
}
+(Heartbeat*)startHeartbeatProcess:(id)process withIndicator:(NSProgressIndicator*)progress;
-(void)stop;
-(void)heartbeatThread:(id)ignored;
-(void)updateIndicator;
#end
Process.m
#import "Process.h"
#implementation Process
+(Heartbeat*)startHeartbeatProcess:(id)process withIndicator:(NSProgressIndicator*)progress {
Heartbeat* heartbeat = [Heartbeat new];
heartbeat->monitor = process;
heartbeat->indicator = progress;
heartbeat->thread = [[NSThread alloc]initWithTarget:heartbeat selector:(heartbeatThread:) object:nil]; //'heartbeatThread' undeclared
[heartbeat->thread start];
return heartbeat;
}
-(void)stop {
[thread cancel]; //thread undeclared
}
-(void)heartbeatThread:(id)ignored {
while (![thread isCancelled]) {
//thread undeclared
[self performSelectorOnMainThread:#selector(updateIndicator) withObject:nil waitUntilDone:YES];
[NSThread sleepForTimeInterval:0.5];
}
}
-(void)updateIndicator {
[indicator setDoubleValue:monitor.progress];
}
#end
Could not find the setDoubleValue method in the class NSProgressIndicator.
Could not find the setDoubleValue method in the class NSProgressIndicator
For this one, that's because NSProgressIndicator is part of AppKit (the Cocoa GUI library), and you're only linking against Foundation (which is the non-GUI stuff). It seems in your code you've attempted to define an interface for NSProgressIndicator yourself, but you haven't declared any methods on it — that's why it's complaining about not being able to find the setDoubleValue method.
What should you do about it? Well, if you're wanting to use Cocoa's GUI stuff, you need to structure your program in the way Cocoa's GUI system expects. In Xcode, if you create a new Cocoa application it should give you a sample project to build on. In particular, your main() function should contain return NSApplicationMain(argc, (const char **) argv);, which handles starting a run loop to receive events.
If you just want to learn about threading, it may be better to abandon trying to get GUI stuff in the same program, and adapt your code to just print stuff to the console instead.
I find it hard to believe that this is an example from a book, since it seems fairly fundamentally broken!
Other errors I found when I tried running it:
Expected ')' before ':' token
This is on the line heartbeat->thread = [[NSThread alloc]initWithTarget:heartbeat selector:(heartbeatThread:) object:nil];.
The problem there is the syntax for declaring a selector: instead of just saying selector:(heartbeatThread:), you need to say selector:#selector(heartbeatThread:).
'thread' undeclared (first use in this function'
In your header file, you claimed that the class Heartbeat has a method called stop. (That is, you defined -(void)stop; in the #interface section for the Heartbeat class).
However, you implemented that method in the #implementation section for the Process class.
You'd make it easier for yourself if you had one pair of .h and .m files per class, rather than trying to cram multiple class definitions into a single pair of files. That way you could make sure you were putting the implementation of the stop method in the correct class's .m file.
property 'progress' requires method '-progress' to be defined - use #synthesize, #dynamic or provide a method implementation
In the implementation for process you defined an #property called progress. If you define a property, you either have to write getters and setters for it yourself, or write #synthesize progress within your implementation. Doing the latter is equivalent to Objective-C generating your getters and setters automatically at runtime.
thread is not a member of the Process class; it belongs to the Heartbeat class. You have to define a member in the Process class to keep a reference on the Heartbeat instance so you can call methods on its thread member.

Creating an abstract class in Objective-C

I'm originally a Java programmer who now works with Objective-C. I'd like to create an abstract class, but that doesn't appear to be possible in Objective-C. Is this possible?
If not, how close to an abstract class can I get in Objective-C?
Typically, Objective-C class are abstract by convention only—if the author documents a class as abstract, just don't use it without subclassing it. There is no compile-time enforcement that prevents instantiation of an abstract class, however. In fact, there is nothing to stop a user from providing implementations of abstract methods via a category (i.e. at runtime). You can force a user to at least override certain methods by raising an exception in those methods implementation in your abstract class:
[NSException raise:NSInternalInconsistencyException
format:#"You must override %# in a subclass", NSStringFromSelector(_cmd)];
If your method returns a value, it's a bit easier to use
#throw [NSException exceptionWithName:NSInternalInconsistencyException
reason:[NSString stringWithFormat:#"You must override %# in a subclass", NSStringFromSelector(_cmd)]
userInfo:nil];
as then you don't need to add a return statement from the method.
If the abstract class is really an interface (i.e. has no concrete method implementations), using an Objective-C protocol is the more appropriate option.
No, there is no way to create an abstract class in Objective-C.
You can mock an abstract class - by making the methods/ selectors call doesNotRecognizeSelector: and therefore raise an exception making the class unusable.
For example:
- (id)someMethod:(SomeObject*)blah
{
[self doesNotRecognizeSelector:_cmd];
return nil;
}
You can also do this for init.
Just riffing on #Barry Wark's answer above (and updating for iOS 4.3) and leaving this for my own reference:
#define mustOverride() #throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:#"%s must be overridden in a subclass/category", __PRETTY_FUNCTION__] userInfo:nil]
#define methodNotImplemented() mustOverride()
then in your methods you can use this
- (void) someMethod {
mustOverride(); // or methodNotImplemented(), same thing
}
Notes: Not sure if making a macro look like a C function is a good idea or not, but I'll keep it until schooled to the contrary. I think it's more correct to use NSInvalidArgumentException (rather than NSInternalInconsistencyException) since that's what the runtime system throws in response to doesNotRecognizeSelector being called (see NSObject docs).
The solution I came up with is:
Create a protocol for everything you want in your "abstract" class
Create a base class (or maybe call it abstract) that implements the protocol. For all the methods you want "abstract" implement them in the .m file, but not the .h file.
Have your child class inherit from the base class AND implement the protocol.
This way the compiler will give you a warning for any method in the protocol that isn't implemented by your child class.
It's not as succinct as in Java, but you do get the desired compiler warning.
From the Omni Group mailing list:
Objective-C doesn't have the abstract compiler construct like Java at
this time.
So all you do is define the abstract class as any other normal class
and implement methods stubs for the abstract methods that either are
empty or report non-support for selector. For example...
- (id)someMethod:(SomeObject*)blah
{
[self doesNotRecognizeSelector:_cmd];
return nil;
}
I also do the following to prevent the initialization of the abstract
class via the default initializer.
- (id)init
{
[self doesNotRecognizeSelector:_cmd];
[self release];
return nil;
}
Instead of trying to create an abstract base class, consider using a protocol (similar to a Java interface). This allows you to define a set of methods, and then accept all objects that conform to the protocol and implement the methods. For example, I can define an Operation protocol, and then have a function like this:
- (void)performOperation:(id<Operation>)op
{
// do something with operation
}
Where op can be any object implementing the Operation protocol.
If you need your abstract base class to do more than simply define methods, you can create a regular Objective-C class and prevent it from being instantiated. Just override the - (id)init function and make it return nil or assert(false). It's not a very clean solution, but since Objective-C is fully dynamic, there's really no direct equivalent to an abstract base class.
This thread is kind of old, and most of what I want to share is already here.
However, my favorite method is not mentioned, and AFAIK there’s no native support in the current Clang, so here I go…
First, and foremost (as others have pointed out already) abstract classes are something very uncommon in Objective-C — we usually use composition (sometimes through delegation) instead. This is probably the reason why such a feature doesn’t already exist in the language/compiler — apart from #dynamic properties, which IIRC have been added in ObjC 2.0 accompanying the introduction of CoreData.
But given that (after careful assessment of your situation!) you have come to the conclusion that delegation (or composition in general) isn’t well suited to solving your problem, here’s how I do it:
Implement every abstract method in the base class.
Make that implementation [self doesNotRecognizeSelector:_cmd];…
…followed by __builtin_unreachable(); to silence the warning you’ll get for non-void methods, telling you “control reached end of non-void function without a return”.
Either combine steps 2. and 3. in a macro, or annotate -[NSObject doesNotRecognizeSelector:] using __attribute__((__noreturn__)) in a category without implementation so as not to replace the original implementation of that method, and include the header for that category in your project’s PCH.
I personally prefer the macro version as that allows me to reduce the boilerplate as much as possible.
Here it is:
// Definition:
#define D12_ABSTRACT_METHOD {\
[self doesNotRecognizeSelector:_cmd]; \
__builtin_unreachable(); \
}
// Usage (assuming we were Apple, implementing the abstract base class NSString):
#implementation NSString
#pragma mark - Abstract Primitives
- (unichar)characterAtIndex:(NSUInteger)index D12_ABSTRACT_METHOD
- (NSUInteger)length D12_ABSTRACT_METHOD
- (void)getCharacters:(unichar *)buffer range:(NSRange)aRange D12_ABSTRACT_METHOD
#pragma mark - Concrete Methods
- (NSString *)substringWithRange:(NSRange)aRange
{
if (aRange.location + aRange.length >= [self length])
[NSException raise:NSInvalidArgumentException format:#"Range %# exceeds the length of %# (%lu)", NSStringFromRange(aRange), [super description], (unsigned long)[self length]];
unichar *buffer = (unichar *)malloc(aRange.length * sizeof(unichar));
[self getCharacters:buffer range:aRange];
return [[[NSString alloc] initWithCharactersNoCopy:buffer length:aRange.length freeWhenDone:YES] autorelease];
}
// and so forth…
#end
As you can see, the macro provides the full implementation of the abstract methods, reducing the necessary amount of boilerplate to an absolute minimum.
An even better option would be to lobby the Clang team to providing a compiler attribute for this case, via feature requests. (Better, because this would also enable compile-time diagnostics for those scenarios where you subclass e.g. NSIncrementalStore.)
Why I Choose This Method
It get’s the job done efficiently, and somewhat conveniently.
It’s fairly easy to understand. (Okay, that __builtin_unreachable() may surprise people, but it’s easy enough to understand, too.)
It cannot be stripped in release builds without generating other compiler warnings, or errors — unlike an approach that’s based on one of the assertion macros.
That last point needs some explanation, I guess:
Some (most?) people strip assertions in release builds. (I disagree with that habit, but that’s another story…) Failing to implement a required method — however — is bad, terrible, wrong, and basically the end of the universe for your program. Your program cannot work correctly in this regard because it is undefined, and undefined behavior is the worst thing ever. Hence, being able to strip those diagnostics without generating new diagnostics would be completely unacceptable.
It’s bad enough that you cannot obtain proper compile-time diagnostics for such programmer errors, and have to resort to at-run-time discovery for these, but if you can plaster over it in release builds, why try having an abstract class in the first place?
Using #property and #dynamic could also work. If you declare a dynamic property and don't give a matching method implementation, everything will still compile without warnings, and you'll get an unrecognized selector error at runtime if you try to access it. This essentially the same thing as calling [self doesNotRecognizeSelector:_cmd], but with far less typing.
In Xcode (using clang etc) I like to use __attribute__((unavailable(...))) to tag the abstract classes so you get an error/warning if you try and use it.
It provides some protection against accidentally using the method.
Example
In the base class #interface tag the "abstract" methods:
- (void)myAbstractMethod:(id)param1 __attribute__((unavailable("You should always override this")));
Taking this one-step further, I create a macro:
#define UnavailableMacro(msg) __attribute__((unavailable(msg)))
This lets you do this:
- (void)myAbstractMethod:(id)param1 UnavailableMacro(#"You should always override this");
Like I said, this is not real compiler protection but it's about as good as your going to get in a language that doesn't support abstract methods.
The answer to the question is scattered around in the comments under the already given answers. So, I am just summarising and simplifying here.
Option1: Protocols
If you want to create an abstract class with no implementation use 'Protocols'. The classes inheriting a protocol are obliged to implement the methods in the protocol.
#protocol ProtocolName
// list of methods and properties
#end
Option2: Template Method Pattern
If you want to create an abstract class with partial implementation like "Template Method Pattern" then this is the solution.
Objective-C - Template methods pattern?
Another alternative
Just check the class in the Abstract class and Assert or Exception, whatever you fancy.
#implementation Orange
- (instancetype)init
{
self = [super init];
NSAssert([self class] != [Orange class], #"This is an abstract class");
if (self) {
}
return self;
}
#end
This removes the necessity to override init
(more of a related suggestion)
I wanted to have a way of letting the programmer know "do not call from child" and to override completely (in my case still offer some default functionality on behalf of the parent when not extended):
typedef void override_void;
typedef id override_id;
#implementation myBaseClass
// some limited default behavior (undesired by subclasses)
- (override_void) doSomething;
- (override_id) makeSomeObject;
// some internally required default behavior
- (void) doesSomethingImportant;
#end
The advantage is that the programmer will SEE the "override" in the declaration and will know they should not be calling [super ..].
Granted, it is ugly having to define individual return types for this, but it serves as a good enough visual hint and you can easily not use the "override_" part in a subclass definition.
Of course a class can still have a default implementation when an extension is optional. But like the other answers say, implement a run-time exception when appropriate, like for abstract (virtual) classes.
It would be nice to have built in compiler hints like this one, even hints for when it is best to pre/post call the super's implement, instead of having to dig through comments/documentation or... assume.
If you are used to the compiler catching abstract instantiation violations in other languages, then the Objective-C behavior is disappointing.
As a late binding language it is clear that Objective-C cannot make static decisions on whether a class truly is abstract or not (you might be adding functions at runtime...), but for typical use cases this seems like a shortcoming. I would prefer the compiler flat-out prevented instantiations of abstract classes instead of throwing an error at runtime.
Here is a pattern we are using to get this type of static checking using a couple of techniques to hide initializers:
//
// Base.h
#define UNAVAILABLE __attribute__((unavailable("Default initializer not available.")));
#protocol MyProtocol <NSObject>
-(void) dependentFunction;
#end
#interface Base : NSObject {
#protected
__weak id<MyProtocol> _protocolHelper; // Weak to prevent retain cycles!
}
- (instancetype) init UNAVAILABLE; // Prevent the user from calling this
- (void) doStuffUsingDependentFunction;
#end
//
// Base.m
#import "Base.h"
// We know that Base has a hidden initializer method.
// Declare it here for readability.
#interface Base (Private)
- (instancetype)initFromDerived;
#end
#implementation Base
- (instancetype)initFromDerived {
// It is unlikely that this becomes incorrect, but assert
// just in case.
NSAssert(![self isMemberOfClass:[Base class]],
#"To be called only from derived classes!");
self = [super init];
return self;
}
- (void) doStuffUsingDependentFunction {
[_protocolHelper dependentFunction]; // Use it
}
#end
//
// Derived.h
#import "Base.h"
#interface Derived : Base
-(instancetype) initDerived; // We cannot use init here :(
#end
//
// Derived.m
#import "Derived.h"
// We know that Base has a hidden initializer method.
// Declare it here.
#interface Base (Private)
- (instancetype) initFromDerived;
#end
// Privately inherit protocol
#interface Derived () <MyProtocol>
#end
#implementation Derived
-(instancetype) initDerived {
self= [super initFromDerived];
if (self) {
self->_protocolHelper= self;
}
return self;
}
// Implement the missing function
-(void)dependentFunction {
}
#end
Probably this kind of situations should only happen at development time, so this might work:
- (id)myMethodWithVar:(id)var {
NSAssert(NO, #"You most override myMethodWithVar:");
return nil;
}
You can use a method proposed by #Yar (with some modification):
#define mustOverride() #throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:#"%s must be overridden in a subclass/category", __PRETTY_FUNCTION__] userInfo:nil]
#define setMustOverride() NSLog(#"%# - method not implemented", NSStringFromClass([self class])); mustOverride()
Here you will get a message like:
<Date> ProjectName[7921:1967092] <Class where method not implemented> - method not implemented
<Date> ProjectName[7921:1967092] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[<Base class (if inherited or same if not> <Method name>] must be overridden in a subclass/category'
Or assertion:
NSAssert(![self respondsToSelector:#selector(<MethodName>)], #"Not implemented");
In this case you will get:
<Date> ProjectName[7926:1967491] *** Assertion failure in -[<Class Name> <Method name>], /Users/kirill/Documents/Projects/root/<ProjectName> Services/Classes/ViewControllers/YourClass:53
Also you can use protocols and other solutions - but this is one of the simplest ones.
Cocoa doesn’t provide anything called abstract. We can create a class abstract which gets checked only at runtime, and at compile time this is not checked.
I usually just disable the init method in a class that I want to abstract:
- (instancetype)__unavailable init; // This is an abstract class.
This will generate an error at compile time whenever you call init on that class. I then use class methods for everything else.
Objective-C has no built-in way for declaring abstract classes.
Changing a little what #redfood suggested by applying #dotToString's comment, you actually have the solution adopted by Instagram's IGListKit.
Create a protocol for all the methods that make no sense to be defined in the base (abstract) class i.e. they need specific implementations in the children.
Create a base (abstract) class that does not implement this protocol. You can add to this class any other methods that make sense to have a common implementation.
Everywhere in your project, if a child from AbstractClass must be input to or output by some method, type it as AbstractClass<Protocol> instead.
Because AbstractClass does not implement Protocol, the only way to have an AbstractClass<Protocol> instance is by subclassing. As AbstractClass alone can't be used anywhere in the project, it becomes abstract.
Of course, this doesn't prevent unadvised developers from adding new methods referring simply to AbstractClass, which would end up allowing an instance of the (not anymore) abstract class.
Real world example: IGListKit has a base class IGListSectionController which doesn't implement the protocol IGListSectionType, however every method that requires an instance of that class, actually asks for the type IGListSectionController<IGListSectionType>. Therefore there's no way to use an object of type IGListSectionController for anything useful in their framework.
In fact, Objective-C doesn't have abstract classes, but you can use Protocols to achieve the same effect. Here is the sample:
CustomProtocol.h
#import <Foundation/Foundation.h>
#protocol CustomProtocol <NSObject>
#required
- (void)methodA;
#optional
- (void)methodB;
#end
TestProtocol.h
#import <Foundation/Foundation.h>
#import "CustomProtocol.h"
#interface TestProtocol : NSObject <CustomProtocol>
#end
TestProtocol.m
#import "TestProtocol.h"
#implementation TestProtocol
- (void)methodA
{
NSLog(#"methodA...");
}
- (void)methodB
{
NSLog(#"methodB...");
}
#end
A simple example of creating an abstract class
// Declare a protocol
#protocol AbcProtocol <NSObject>
-(void)fnOne;
-(void)fnTwo;
#optional
-(void)fnThree;
#end
// Abstract class
#interface AbstractAbc : NSObject<AbcProtocol>
#end
#implementation AbstractAbc
-(id)init{
self = [super init];
if (self) {
}
return self;
}
-(void)fnOne{
// Code
}
-(void)fnTwo{
// Code
}
#end
// Implementation class
#interface ImpAbc : AbstractAbc
#end
#implementation ImpAbc
-(id)init{
self = [super init];
if (self) {
}
return self;
}
// You may override it
-(void)fnOne{
// Code
}
// You may override it
-(void)fnTwo{
// Code
}
-(void)fnThree{
// Code
}
#end
Can't you just create a delegate?
A delegate is like an abstract base class in the sense that you say what functions need to be defined, but you don't actually define them.
Then whenever you implement your delegate (i.e abstract class) you are warned by the compiler of what optional and mandatory functions you need to define behavior for.
This sounds like an abstract base class to me.