Objective-c: How can I require override and not call super? - ios

I guess this is solved by writing a #protocol.
But I'm hungry for knowledge. Is there some flag or other way to require subclasses to override specific methods and not call super? Like the opposite of NS_REQUIRES_SUPER / objc_requires_super?

I do that in code not using any flags.
- I add assertion in the method of the super class that needs to be overridden in case this method is get called
Here I have a class that have a method fetchUserData that should be overridden by the child class
- (void)fetchUserData
{
NSString *descrip = [NSString stringWithFormat:#"child implementation for method:%# : %#",NSStringFromSelector(_cmd), NSStringFromClass([self class])
NSAssert(NO, descrip);
}

If I understand this right you're essentially asking how to make an abstract class... forcing subclasses to implement methods.
Check out : Creating an abstract class in Objective-C
In short, have the method throw an exception.

There are some things here that should be useful.
Specifically subclassResponsibility:
EDIT: Good point in the comments - GNUStep != Foundation. In other words, the methods on the page I linked to should be used with caution. However, I've personally used subclassResponsibility: and it works.

Related

Objective C: Declaring a selector but implementing it in objects category

I have a framework in obj-c which is included by other modules. I want to allow the modules which are going to include it to provide their own implementation for certain methods.
I can't use subclassing because of some issues around serializing these objects. So, have to rely on using category.
I am thinking of declaring a method/selector for the object and then modules will define the category and implement that method. Something like below:
Framework will declare interface like below:
#interface framework:NSObject
- (void)methodToBeImplemented;
#end
#implementation framework()
- (void)invokeClientDefinedMethod
{
if([self respondsToSelector:#(methodToBeImplemented)]) {
[self methodToBeImplemented];
}
}
//Module-1 will link against this framework and define the category
#implementation framework(methodImplementor)
- (void)methodToBeImplemented
{
...
}
#end
Can I choose not to implement methodToBeImplemented at all in framework and implementation to be provided by the modules themselves.
I know that I can do it performSelector route. But I cringe to do so because I want to send pointers to my method which is not really possible with performSelector
If possible, I would highly recommend using a delegate pattern for your object so that callers can pass a delegate that conforms to a protocol rather than directly extending the class. That's the normal way to implement this kind of system. But if there's a particular reason a delegate is not possible, you can build what you're describing.
What you're looking for is an informal protocol, which is how almost all protocols were handled prior to the introduction of #optional.
What you want to do is define a category on your class in your public header:
#interface Framework (OverridePoints)
- (void)methodToBeImplemented
#end
This declares that such a method may exist, but it does not enforce its actually being implemented. The key is having a name in the parentheses. This can be anything (I used "OverridePoints" here), but it cannot be empty since that would be an extension instead of a category.
Once you have that, then the rest of your ideas work. You can test for respondsToSelector:, and the consumer can implement (or not implement) the category methods just as you describe.
The one danger is that there is nothing preventing multiple parts of the program implementing the same method in categories. That is undefined behavior, but the compiler will not catch it for you.

Difference between method swizzling and category in Objective c

I was just understanding the method swizzling done in obj c Method Swizzling and dangers of using method swizzling and couldn't help but draw a comparison between doing method swizzling and overwriting method implementation using categories.
They both help override the functionality of the predefined framework methods.
So is there any difference between the two or they can be used interchangeably?
The main difference is that Objective C prevents you from invoking the original implementation from a category override. This is because Objective-C's super invocations start from the super-class, while categories override methods on the same class level.
Method swizzling, on the other hand, lets you keep a reference to the original implementation as well, so that you could call it from inside your implementation. For example, in the article at your first link the author writes this:
- (void) logged_viewDidAppear:(BOOL)animated {
[self logged_viewDidAppear:animated];
NSLog(#"logged view did appear for %#", [self class]);
}
The second line makes a call to logged_viewDidAppear: method, which looks like an unconditional call to itself that should cause infinite recursion. However, this is not what happens: after swizzling, this call gets transformed into a call to the original viewDidAppear: because of the way method swizzling works.
In contrast, overriding a method from a category does not give you access to the logic of the method that you are overriding. It lets you replace the logic, but it does not let you extend it.
extension UIViewController{
public func myViewDidLoad(){
self.viewDidLoad()
//but you need to call this method everywhere replacing
}
//you cant do this
public func viewDidLoad(){
self.viewDidLoad()
//my code
}
}
Categories or extension let you do these:
Add computed properties and computed type properties
Define instance methods and type methods
Provide new initializers
Define subscripts
Define and use new nested types
Make an existing type conform to a protocol
(from Apple)
They don't let you extend original method of the same class that you are extending and if you try like the above code method signature conflict pops up.
You might want to check this website to get the concept diagrammatically. I really loved it.
http://matteogobbi.github.io/blog/2014/12/15/extending-methods-in-a-category-by-method-swizzling/
Make sure to check this awesome article for good implementation detail:
http://nshipster.com/method-swizzling/

objective-c/ios track screen usage

Let's say, for instance, that I want to place some code in the viewDidAppear: method for all UIViewController (including subclasses) objects from my project:
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
NSLog(#"Did show: %#:%#", NSStringFromClass([self class]), self.title);
}
Is there a way to do this without using categories (for UIViewController), and without having to manually change the superclass of all my view controllers to a new class that defines this method?
The reason I don't want to use a category is because I might want to define methods and call their super implementation.
For instance, is it possible to automatically add an intermediary class between UIViewController and whatever other classes inherit from UIViewController at runtime (or using preprocessor macros)?
The common way to achieve this is called method swizzling. Mike Ash has an article of how to do this correctly.
The general idea is to exchange the original implementation of an Objective-C method. Usually you call through to the original implementation from the inserted function/method.
Here's a quote from Mike's article:
The Obligatory Warning
Overriding methods on classes you don't own is a dangerous business. Your override could cause problems by breaking the assumptions of the class in question. Avoid it if it's at all possible. If you must do it, code your override with extreme care.

what does do method class in objective c

This might be a silly question. I'm learning objective C (iOS) by studying the code and I came across the expression
[InstanceName class];
What does it do?
I tried to search for class method but It just pops up difference between class method and instance method etc. I guess it might give some sort of class object but I have no idea what is the purpose of the statement.
the original code is Sample Facebook App (scrumptious) using FB SDK....
If you see something like this as a standalone expression....
[InstanceName class];
... then the code is most likely forcing the execution of the +initialize method on said class. The first time any method is invoked on a class, the +initialize method will be invoked prior by the runtime. So, have a look at InstanceName and see if it has a +initialize method.
Note that forcing +initialize to execute in this fashion is a sure sign of bad design. +initialize should never need to be forced like this and should not have execution order dependencies.
There is a legitimate additional reason why this line of code might exist. By referring to InstanceName with a hard reference, it'll force the linker to link in all symbols in the library. (If you don't have a hard reference to at least one symbol in a library -- a .a -- some linkers will simply drop the library from the link unit entirely.)
It gets the class of the object.
So for instance if InstanceName is an instance of class Foo
[InstanceName class]; will return Foo, in a variable of type Class
You can use class_getClassName to get an NSString from this class to log it.
class is a method inherited from NSObject. It lets you get the instance of the class object representing the class of the instance on which the method is called.
It can be used to examine the metadata of the current object. For example, you can use class method to determine if a given object is of a particular class:
if ([sender isKindOfClass:[UIButton class]]) {
...
}
It returns the class of the object. Suppose you have an array of UIView subclasses you created and you want to perform some action only to those who belong to a certain class. You could loop through the array and check for each object's class:
for (id view in myViews) {
if ([view isKindOfClass:[MyUIViewSubclass class]]) {
// Do something
}
}

how to forbid the basic init method in a NSObject

I want to force user to use my own init method (for example -(id)initWithString:(NSString*)foo;) and not the basic [[myObject alloc]init];.
how can I do that?
All other answers here are outdated. There is a way to do this properly now!
While it is easy to just crash at runtime when somebody calls your method, compile-time checking would be far preferable.
Fortunately, this has been possible in Objective-C for a while.
Using LLVM, you can declare any method as unavailable in a class like so
- (void)aMethod __attribute__((unavailable("This method is not available")));
This will make the compiler complain when trying to call aMethod. Great!
Since - (id)init is just an ordinary method, you can prohibit calling of the default (or any other) initializer in this way.
Note, though, that this will not insure against the method being called using the dynamic aspects of the language, for instance via [object performSelector:#selector(aMethod)] etc. In the case of init, you won't even get a warning, because the init method is defined in other classes, and the compiler doesn't know enough to give you an undeclared selector warning.
So, to ensure against this, make sure that the init method crashes when being called (see Adam's answer).
If you want to disallow - (id)init in a framework, make sure to also disallow + (id)new, as this will just forward to init.
Javi Soto has written a small macro to forbid using the designated initializer faster and easier and to give nicer messages. You can find it here.
tl; dr
Swift:
private init() {}
Since all Swift classes include an internal init by default, you can change it to private to keep other classes from calling it.
Objective C:
Put this in your class's .h file.
- (instancetype)init NS_UNAVAILABLE;
This relies on an OS define that prevents the method named from being called.
The accepted answer is incorrect - you CAN do this, and it's very easy, you just have to be a bit explicit. Here's an example:
You have a class named "DontAllowInit" which you want to prevent people init'ing:
#implementation DontAllowInit
- (id)init
{
if( [self class] == [DontAllowInit class])
{
NSAssert(false, #"You cannot init this class directly. Instead, use a subclass e.g. AcceptableSubclass");
self = nil; // as per #uranusjr's answer, should assign to self before returning
}
else
self = [super init];
return nil;
}
Explanation:
When you call [super init], the class that was alloc'd was the SUBCLASS.
"self" is the instance - i.e. the thing that was init'd
"[self class]" is the class that was instantiated - which will be SUBCLASS when the SUBCLASS is calling [super init], or will be the SUPERCLASS when the SUPERCLASS is being called with plain [[SuperClass alloc] init]
So, when the superclass receives an "init" call, it just needs to check whether the alloc'd class is the same as its own class
Works perfectly. NB: I don't recommend this technique for "normal apps" because usually you INSTEAD want to use a Protocol.
HOWEVER ... when writing Libraries ... this technique is VERY valuable: you frequently want to "save (other developers) from themselves", and its easy to NSAssert and tell them "Oops! you tried to alloc/init the wrong class! Try class X instead...".
-(id) init
{
#throw [NSException exceptionWithName: #"MyExceptionName"
reason: #"-init is not allowed, use -initWithString: instead"
userInfo: nil];
}
-(id) initWithString: (NSString*) foo
{
self = [super init]; // OK because it calls NSObject's init, not yours
// etc
Throwing the exception is justified if you document that -init is not allowed and therefore using it is a programmer error. However, a better answer would be to make -init invoke -initWtihString: with some suitable default value i.e.
-(id) init
{
return [self initWithString: #""];
}
Short answer: you can't.
Longer answer: the best practice is to set your most detailed initializer as the designated initializer, as described here. 'init' will then call that initializer with sane, default values.
Another option is to 'assert(0)' or crash in another way inside the 'init', but this isn't a good solution.
I actually voted up Adam's answer, but would like to add some things to it.
First, it is strongly encouraged (as seem in auto-generated init methods in NSObject subclasses) that you check self against nil in inits. Also, I don't think class objects are guaranteed to be "equal" as in ==. I do this more like
- (id)init
{
NSAssert(NO, #"You are doing it wrong.");
self = [super init];
if ([self isKindOfClass:[InitNotAllowedClass class]])
self = nil;
return self;
}
Note that I use isKindOfClass: instead because IMHO if this class disallows init, it should disallow its descendants to have it as well. If one of its subclass want it back (which doesn't make sense for me), it should override it explicitly by calling my designated initializer.
But more importantly, whether you take the above approach or not, you should always have appropriate documentation. You should always clearly state which method is your designated initializer, try as best as you can to remind others not to use inappropriate initializers in documentation, and put some faith in other users/developers, instead of trying to "save everybody else's asses" with clever codes.

Resources