Can I expose Swift default parameter values to Objective-C? - objective-c

Say I have some Swift class with methods I'd like to expose to Objective-C:
#objc(Worker) class Worker : NSObject {
func performWork(label: String = "Regular Work") {
// Perform work
}
}
I can call this in two ways:
Worker().performWork()
Worker().performWork("Swift Development")
However, when called from Objective-C, I do not get the "default" version of this method - I must supply a label:
[[[Worker alloc] init] performWork:#"Obj-C Development"];
See the definition from my AppName-Swift.h header below:
SWIFT_CLASS_NAMED("Worker")
#interface Worker : NSObject
- (void)performWork:(NSString * __nonnull)label;
- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
#end
I would expect to see a method with this signature:
- (void)performWork;
I realise ObjC doesn't support default parameter values, but my assumption was that the Swift default values simply generate additional Swift functions with trivial implementations calling the "real" function (i.e. they're syntactic sugar hiding the typical implementation we'd use in Obj-C).
Is there any way to expose this default value to Objective-C? If not, can anyone point me to any documentation on why this isn't available?

The answer is no, there is currently no way to expose that.
It is however, being considered for Swift 3.0 (see the proposal here)
EDIT: This is incorrect as pointed out by Adam S.

Related

Swift error: class method "someMethod() is unavailable, use object construction Class()"

Objective-C APIs do a lot of object construction using class methods:
+ (NSDate *)date;
+ (NSURL *)urlWithString:(NSString *)string;
+ (instancetype)layerWithSession:(AVCaptureSession *)session
Sometimes I even see these appearing in old Swift tutorials as class methods, but when I try to call them, I get compiler errors like these:
date() is unavailable, use object construction NSDate()
urlWithString() is unavailable, use object construction NSURL(string:)
layerWithSession() is unavailable, use object construction AVCaptureVideoPreviewLayer(session:)
(I see declarations like convenience init(URL url: NSURL) in the docs, and in Xcode's generated Swift interfaces for SDK classes, but what do they have to do with any of this?)
This even happens when I declare class methods in my own ObjC code, like for a singleton pattern:
#interface MyManager: NSObject
+ (instancetype)manager;
#end
When I try to use them from Swift, I get the same kind of errors:
let manager = MyManager.manager()
// error: 'manager()' is unavailable, use object construction 'MyManager()'
What gives? How do I fix these errors?
Swift does away with the alloc/init initialization pattern from Objective-C and replaces it with a construction syntax similar to that seen in Java or C++.
When, in a Swift class interface (or in Apple's documentation), you see something like:
class Thing {
init(number: Int)
}
That means you can create a Thing by calling it with the following "construction syntax":
let thingTwo = Thing(number: 2)
It doesn't matter if it's a class or a struct, or if you see other things like convenience or required or public before init... that's how you use it. (Of course, replace Thing with the type you're using, number with any parameter label(s) in the actual initializer you want, and 2 with an appropriate value for that parameter.)
When classes originally defined in ObjC are imported into Swift, the Swift compiler does a bunch of things to make those APIs look and feel more like native Swift code. One of those things is to replace the common pattern of using class methods as convenience constructors with real initializers.
All the examples from the question:
+ (NSDate *)date;
+ (NSURL *)urlWithString:(NSString *)string;
+ (instancetype)layerWithSession:(AVCaptureSession *)session;
... are such convenience constructors. That means they import into Swift not as class methods (NSDate.date(), NSURL.urlWithString(), etc), but as initializers:
class NSDate {
init()
}
class NSURL {
init?(string: String)
}
class AVCaptureVideoPreviewLayer {
init!(session: AVCaptureSession)
}
... and you call them with object construction syntax:
let date = NSDate()
let url = NSURL(string: "http://apple.com")
let layer = AVCaptureVideoPreviewLayer(session: mySession)
In fact, when you see error messages about "is unavailable, use object construction", Xcode pretty much always offers an automatic fix-it to insert the proper syntax.
How does this work? Swift looks for possible "base names" of a class and matches between those names and the class method / initializer method names. (It also checks for class methods that return an instance of that class, initializers that start with "init...", etc.)
For example, Swift sees the following as a convenience constructor:
#interface PDQMediaManager: NSObject
+ (PDQMediaManager *)manager;
#end
This may be a problem if what you (or the original developer of PDQMediaManager) intend is for that class to act as a singleton, and the +manager method to return the singleton instance — if a Swift developer writes PDQMediaManager(), they'll be constructing a new instance instead of retrieving the singleton.
In this case, one good solution is to rename the singleton method:
+ (PDQMediaManager *)defaultManager;
This won't get seen as a convenience constructor, so Swift clients can call PDQMediaManager.defaultManager() to get the singleton instance.
You can also use the NS_SWIFT_NAME to rename the singleton method only for Swift clients:
+ (PDQMediaManager *)manager NS_SWIFT_NAME(defaultManager());
If you don't control the codebase with the offending method, your best bet is probably to write your own ObjC code to forward to the singleton method and expose that to your Swift code via a bridging header.

Possible to pass object out of IF statement scope?

Here's my code. The compiler is complaining about unused variables within the scope, and use of an undeclared variable out of scope. I understand that. The object would need to be declared before the IF statement so it's accessible from both sides. But here's the twist.
I can't pre-declare the object because what class the object will be from is dependent on the result of the IF statement. Here's the excerpt of code that I'm stuck on.
if (!([self.defaults valueForKey:#"unofficialAPIOn"])) {
MALInterfaceController *interface = [[MALInterfaceController alloc]init];
}
else{
MALControllerUnofficial *interface = [[MALControllerUnofficial alloc]init];
}
[interface verifyAuth:self.usernameField.text forPassword:self.passwordField.text];
Both MALInterfaceController and MALControllerUnofficial are basically the same class that have the same methods, etc but are tailored to two different API's. How can I pass the *interface object upwards?
Why not use the dynamic type id?
id interface;
if (!([self.defaults valueForKey:#"unofficialAPIOn"])) {
interface = [[MALInterfaceController alloc]init];
}
else{
interface = [[MALControllerUnofficial alloc]init];
}
(id<protocolWhichBothClassesConformTo>)[interface verifyAuth:self.usernameField.text forPassword:self.passwordField.text];
Also, does this not mean you should be looking at a refactor if two of your classes have 'same methods etc'
Worth reading https://developer.apple.com/library/ios/documentation/cocoa/conceptual/ProgrammingWithObjectiveC/WorkingwithProtocols/WorkingwithProtocols.html
You state:
Both MALInterfaceController and MALControllerUnofficial are basically the same class that have the same methods, etc but are tailored to two different API's.
You want to consider (a) using a common base class (b) using a protocol or maybe (c) using a class cluster - the last is more obscure so we'll skip that one. Adopting any of these will address your problem.
(a) Common base class. Define a class with the code that is a generic version of what your object does, say MALControllerGeneric, and then create MALInterfaceController and MALControllerUnofficial as subclasses which tailor the generic version for the two different cases. Before your if declare interface to be of type MALControllerGeneric.
(b) Declare the common methods your two classes must provide as a protocol, this lists the methods an class conforming to the protocol must implement. Then declare your two classes as implementing this protocol. In outline this is:
#protocol MALController
- (void) someCommonProcedure;
// etc.
#end
// inherit from NSObject, implement MALController protocol
#interface MALInterfaceController : NSObject<MALController>
// declare methods peculiar to MALInterfaceController (if any)
#end
#implementation MALInterfaceController
// implement protocol
- (void) someCommonProcedure { ... }
...
#end
You then declare interface to be any object which implements the protocol:
id<MALController> interface;
This improves (static) type-checking compared to use the more generic id type.
The choice between (a) and (b) depends on factors such as how much common code can be shared etc., there is no general right answer - you have to pick what suits.
Addendum - After Comment
Using the protocol approach, you should have the code along the lines of:
id<MALController> interface;
if (![self.defaults valueForKey:#"unofficialAPIOn"])
interface = [MALInterfaceController new];
else
interface = [MALControllerUnofficial new];
[interface verifyAuth:self.usernameField.text forPassword:self.passwordField.text];
BTW did you mean to call boolForKey: rather than valueForKey: above?

ObjC: must I specify the inheritance in the header file?

Common examples for a ObjC object are like this (for the header file):
#interface A: B {
int x;
int y;
}
#end
Is it possible to avoid the inheritance specification (i.e. B here) in the header file?
In my case, the framework A defines that class A and another (sub-)framework B defines the class B (which is a subclass of NSView). A links to B. In my application, I link to A and I don't need to know anything about B except that it is a subclass of NSView. And I want to avoid to link to B. But if B is in the header file, I think I cannot avoid it, that's why I was asking about how to avoid it.
No. You have to specify the superclass for any subclass. May I ask why you would want to do something like this?
Your application will need the code for B, therefore you must either link to B's framework, or compile the B framework into your A framework. Either way, you cannot use an instance of A without the code for B, and you must include B's header in your A header.
no.
you must often work around this with a class cluster, hold a private implementation, or create an object factory. then you can minimize the dependencies across modules.
you'll still ultimately need to link to the sub library at some stage if you intend to use it (e.g. create an instance of).
Update - Demonstrate Private Implementations
Private implementations can be entirely opaque. If you do expose them, here are two ways to implement private implementations which are visible to clients:
via protocol:
// MONDrawProtocol.h
// zero linkage required
// needs to be visible to adopt
// may be forwarded
#protocol MONDrawProtocol
- (void)drawView:(NSView *)view inRect:(NSRect)rect;
#end
// MONView.h
#protocol MONDrawProtocol;
#interface MONView : NSView
{
NSObject<MONDrawProtocol>* drawer;
}
#end
// MONView.m
#include "MONDrawProtocol.h"
#implementation MONView
- (void)drawRect:(NSRect)rect
{
[self.drawer drawView:self inRect:rect];
}
#end
via base:
// MONDrawer.h
// base needs to be visible to subclass and types which use MONDrawer
// may be forwarded
#interface MONDrawer : NSObject
- (void)drawView:(NSView *)view inRect:(NSRect)rect;
#end
// MONView.h
#class MONDrawer;
#interface MONView : NSView
{
MONDrawer * drawer;
}
#end
// MONView.m
#include "MONDrawer.h"
#implementation MONView
- (void)drawRect:(NSRect)rect
{
[self.drawer drawView:self inRect:rect];
}
#end
If you don't specify a superclass in the interface, then your class is a root class. This means it doesn't inherit from any other class, so it is responsible for providing its own implementation of the required methods (most of those defined by the NSObject class and protocol). Since this is not a simple task, it is highly encouraged that you inherit from some other class which provides these methods.
Yes you can, with that you will also lost default implementations of alloc, init, etc. Which makes you write your own alloc, init and other stuffs which was there in NSObject
can't you just include a mock version of the class you're inheriting from A's header itself? Not sure if that will cause problems, but it would allow you to clean up your linking requrirements a bit. B-new could then be a category of B'Original
I have one solution now. Instead of providing the class, I just provide a function like this:
NSView* allocA();
Internally in the framework A, A is a subclass of B.

How do I provide a default implementation for an Objective-C protocol?

I'd like to specify an Objective-C protocol with an optional routine. When the routine is not implemented by a class conforming to the protocol I'd like to use a default implementation in its place. Is there a place in the protocol itself where I can define this default implementation? If not, what is the best practice to reduce copying and pasting this default implementation all over the place?
Objective-C protocols have no affordance for default implementations. They are purely collections of method declarations that can be implemented by other classes. The standard practice in Objective-C is to test an object at runtime to see if it responds to the given selector before calling that method on it, using -[NSObject respondsToSelector:]. If e object does not respond to the given selector, the method isn't called.
One way you could achieve the result you're looking for would be to define a method encapsulating the default behavior you're looking for in the calling class, and call that method if the object doesn't pass the test.
Another approach would be to make the method be required in the protocol, and provide default implementations in the superclasses of any classes wherein you may not want to provide a specific implementation.
There are probably other options as well, but generally speaking there isn't a particular standard practice in Objective-C, except perhaps to just not call the given method if it hasn't been implement by the object, per my first paragraph, above.
There is no standard way for doing that as protocols should not define any implementations.
Since Objective-C comes with a neat runtime, you can of course add such a behavior if you really think you need to do it that way (and there's no possibility by achieving the same with inheritance).
Say you declared MyProtocol, then just add an interface with the same name in the .h file under your protocol declaration:
#interface MyProtocol : NSObject <MyProtocol>
+ (void)addDefaultImplementationForClass:(Class)conformingClass;
#end
And create a corresponding implementation file (using MAObjCRuntime for readability here, but the standard runtime functions wouldn't be much more code):
#implementation MyProtocol
+ (void)addDefaultImplementationForClass:(Class)conformingClass {
RTProtocol *protocol = [RTProtocol protocolWithName:#"MyProtocol"];
// get all optional instance methods
NSArray *optionalMethods = [protocol methodsRequired:NO instance:YES];
for (RTMethod *method in optionalMethods) {
if (![conformingClass rt_methodForSelector:[method selector]]) {
RTMethod *myMethod = [self rt_methodForSelector:[method selector]];
// add the default implementation from this class
[conformingClass rt_addMethod:myMethod];
}
}
}
- (void)someOptionalProtocolMethod {
// default implementation
// will be added to any class that calls addDefault...: on itself
}
Then you just have to call
[MyProtocol addDefaultImplementationForClass:[self class]];
in the initializer of your class conforming to the protocol and all default methods will be added.
A truly fascinating way is to use the runtime. At the start-up, very early in the program execution, do the following:
Enumerate all the classes, find classes which implement the protocol
Check if the class implements a method
If not, add to the class the default implementation
It can be achieved without that much trouble.
I agree with "w.m." A very nice solution is to put all the default implementations into an interface (with the same name as the protocol). In the "+initialize" method of any subclass it can simply copy any unimplemented methods from the default interface into itself.
The following helper functions worked for me
#import <objc/runtime.h>
// Get the type string of a method, such as "v#:".
// Caller must allocate sufficent space. Result is null terminated.
void getMethodTypes(Method method, char*result, int maxResultLen)
{
method_getReturnType(method, result, maxResultLen - 1);
int na = method_getNumberOfArguments(method);
for (int i = 0; i < na; ++i)
{
unsigned long x = strlen(result);
method_getArgumentType(method, i, result + x, maxResultLen - 1 - x);
}
}
// This copies all the instance methods from one class to another
// that are not already defined in the destination class.
void copyMissingMethods(Class fromClass, Class toClass)
{
// This gets the INSTANCE methods only
unsigned int numMethods;
Method* methodList = class_copyMethodList(fromClass, &numMethods);
for (int i = 0; i < numMethods; ++i)
{
Method method = methodList[i];
SEL selector = method_getName(method);
char methodTypes[50];
getMethodTypes(method, methodTypes, sizeof methodTypes);
if (![toClass respondsToSelector:selector])
{
IMP methodImplementation = class_getMethodImplementation(fromClass, selector);
class_addMethod(toClass, selector, methodImplementation, methodTypes);
}
}
free(methodList);
}
Then you call it in your class initializer such as...
#interface Foobar : NSObject<MyProtocol>
#end
#implementation Foobar
+(void)initialize
{
// Copy methods from the default
copyMissingMethods([MyProtocol class], self);
}
#end
Xcode will give you warnings about Foobar missing methods, but you can ignore them.
This technique only copies methods, not ivars. If the methods are accessing data members that do not exist, you could get strange bugs. You must ensure that the data is compatible with the code. It is as if you did a reinterpret_cast from Foobar to MyProtocol.
As Ryan mention there are no default implementations for protocols, another option to implementing in the superclass would be is to implement a "Handler" kind of class that can be contained in any class that want to provide the default implementation, the appropriate method then calls the default handlers implementation.
I ended up creating a macro that has a default implementation of the method.
I've defined it in the protocol's header file, and then it's just a one-liner in each implementation.
This way, I do not have to change the implementation several places, and it's done on compile time, so no run-time magic is necessary.

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.