Category Or Extention -- Which one will have precedence - swift

I write awakeFromXib in UILabel category plus Swift UILabel extension.
Now I add one brand new UILabel on ViewController (no outlet created).
awakeFromNib is being called from the category and not from Swift extension.
Please guide which one will have precedence and in what circumstances.
Note: ViewController parent class is written in Swift.

First of all - neither Swift extensions nor Objective-C categories should be used to override non-inherited methods (methods already defined in the class being extended). Apple mentions it in both Swift Developer Guide..:
Extensions can add new functionality to a type, but they can’t override existing functionality.
..And Programming with Objective-C documentations:
If the name of a method declared in a category is the same as a method in the original class, or a method in another category on the same class (or even a superclass), the behavior is undefined as to which method implementation is used at runtime.
If you look for a written "contract", it's emphasised in the quoted text above: if a method is defined in an extensions of a Swift class which itself is a subclass of NSObject (and UILabel is indirect subclass of NSObject) it gets dispatched with messaging mechanism (just like a method defined in an Objective-C category). Thus both methods follow the same Objective-C rules, dispatched the same way, have the same name and the same set of arguments. According to the Apple's own documentation in regards to Objective-C categories it means that the behavior is undefined.
You can probably find empirically some general pattern, but it is not guaranteed to be consistent (can work differently between or even within the same application session) and is a subject to change in future releases.
P.S. It's also double-discouraged to "shadow" Cocoa/Cocoa touch framework classes methods since you may end with suppressing the class own implementation from being called and consequently breaking the dependent logic.

Related

Add an extension/method to all objects in Swift

In Objective-C, all objects can be treated as type id, and nearly all objects inherit from NSObject. (Blocks don't, but that's about the only exception.)
Thus it's possible to create an Objective-C category that extends ALL Objective-C objects. (ignoring blocks)
In Objective-C, I created an extension to NSObject that uses associated objects to optionally attach a dictionary to any NSObject. That enabled me to implement methods setAssocValue:forKey: and assocValueForKey: that makes it possible to attach a key/value pair to any NSObject. This is useful in lots of circumstances.
It makes it possible to add stored properties to a category, just for example. You just write a getter/setter that uses the associated value methods to attach a stored object, and away you go.
It also makes it possible to attach values to existing system objects at runtime. You can hang data or blocks of code on buttons, or do whatever you need to do.
I'd like to do the same thing in Swift.
However, Swift does not have a common base class for all objects like Objective-C does. AnyObject and Any are protcols.
Thus,
extension AnyObject
Won't compile.
I'm at a loss as to where to "attach" my setAssocValue:forKey: and assocValueForKey: methods in Swift.
I could create a base class for my extension, but that defeats the point of using an extension. I could make my base object an Objective-C NSObject, but that means all my objects have to be NSObjects, and Swift objects are not NSObjects by default.
(BTW, this question applies to both the Mac OS and iOS platforms)
No. You've pretty much answered your own question--Swift objects don't have a base class, and the only real way to get around it is to inherit from NSObject.

Why is there no universal base class in Swift?

The documentation says
NOTE
Swift classes do not inherit from a universal base class. Classes you
define without specifying a superclass automatically become base
classes for you to build upon.”
Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks.
It doesn't make much sense to me. There is a reason why Objective-C has a universal base class, and the same reason should apply to Swift, does it? NSObject manages retain/release semantics, a default implementation for isEqual:, hash and description. All this functionality is available in Swift too.
(Objective-C and Swift use the same runtime...)
So, what's up with that? Are Swift classes with no defined superclasses just NSObjects that pose as proper root classes under the hood? Or is the default object-behaviour duplicated for each new root-class? Or have they created another Swift-baseclass? The implementation of retain and release is really complex, because it needs to take multithreading and weak references into account at the same time.
Is there maybe a universal base class in Swift (despite what the documentation says)? It would be really handy, because in Objective-C I can e.g. write extensions that let me coalesce method invocations to the main runloop like [obj.eventually updateCounter] which can be read as "call -updateCounter the next time the main runloop gets in control. If, in the meantime, I call this method again, it should be called only once anyways. With this extension one could implement -[UIView setNeedsDisplay] as [self.eventually display]; This is no longer possible in Swift if there is no universal base class (or maybe it is, who knows?)
There are several object-oriented languages where one can define new root classes, including C++, PHP, and Objective-C, and they work fine, so this is definitely not a special thing.
There is a reason why Objective-C has a universal base class
As Sulthan mentioned, this is not true. There are multiple root classes in Objective-C, and you can define a new root class by simply not specifying a superclass. As Sulthan also mentioned, Cocoa itself has several root classes, NSObject, NSProxy, and Object (the root class of Protocol in ObjC 1.0).
The original Objective-C language was very flexible and someone could in theory come along and create his own root class and create his own framework that is completely different from Foundation, and uses methods completely different from retain, release, alloc, dealloc, etc., and could even implement a completely different way of memory management if he wanted. This flexibility is one of the things so amazing about the bare Objective-C language -- it simply provides a thin layer, all the other things like how objects are created and destroyed, memory management, etc., can all be determined by the user frameworks sitting on top.
However, with Apple's Objective-C 2.0 and modern runtime, more work needed to be done to make your own root class. And with the addition of ARC, in order to use your objects in ARC, you must implement Cocoa's memory management methods like retain and release. Also, to use your objects in Cocoa collections, your class must also implement things like isEqual: and hash.
So in modern Cocoa/Cocoa Touch development, objects generally must at least implement a basic set of methods, which are the methods in the NSObject protocol. All the root classes in Cocoa (NSObject, NSProxy) implement the NSObject protocol.
So, what's up with that? Are Swift classes with no defined
superclasses just NSObjects that pose as proper root classes under the
hood? Or is the default object-behaviour duplicated for each new
root-class? Or have they created another Swift-baseclass?
This is a good question, and you can find out by introspection with the Objective-C runtime. All objects in Swift are, in a sense, also Objective-C objects, in that they can be used with the Objective-C runtime just like objects from Objective-C. Some members of the class (the ones not marked #objc or dynamic) may not be visible to Objective-C, but otherwise all the introspection features of the Objective-C runtime work fully on objects of pure Swift classes. Classes defined in Swift look like any other class to the Objective-C runtime, except the name is mangled.
Using the Objective-C runtime, you can discover that for a class that is a root class in Swift, from the point of view of Objective-C, it actually has a superclass named SwiftObject. And this SwiftObject class implements the methods of the NSObject protocol like retain, release, isEqual:, respondsToSelector:, etc. (though it does not actually conform to the NSObject protocol). This is how you can use pure Swift objects with Cocoa APIs without problem.
From inside Swift itself, however, the compiler does not believe that a Swift root class implements these methods. So if you define a root class Foo, then if you try to call Foo().isKindOfClass(Foo.self), it will not compile it complaining that this method does not exist. But we can still use it with a trick -- recall that the compiler will let us call any Objective-C method (which the compiler has heard of) on a variable of type AnyObject, and the method lookup produces an implicitly-unwrapped optional function that succeeds or fails at runtime. So what we can do is cast to AnyObject, make sure to import Foundation or ObjectiveC (so the declaration is visible to the compiler), we can then call it, and it will work at runtime:
(Foo() as AnyObject).isKindOfClass(Foo.self)
So basically, from the Objective-C point of view, a Swift class either has an existing Objective-C class as root class (if it inherited from an Objective-C class), or has SwiftObject as root class.
This is mainly a design decision, there are languages which have a root class (e.g. Java) and languages which don't (e.g. C++).
Note that in Obj-C a root class is not enforced. You can easily create an object which doesn't inherit from any class. You can also create your own root classes, there are at least 3 in the Apple API (NSObject, NSProxy and deprecated Object).
The reason to have a root class is mostly historical - the root class ensures that all objects have some common interface, some common methods (e.g. isEqualTo:, hash() etc.) which are necessary for collection classes to work.
Once you have generics (or templates in C++), having a root class is not so important any more.
retain and release in NSObject are not important anymore since ARC. With MRC, you were still required to call them. With ARC you never call the methods explicitly and they can be implemented more efficiently behind the scenes.
In Swift, the methods from NSObject have been divided into protocols - Equatable, Hashable, Printable and DebugPrintable. That has the advantage that objects can share interfaces with structs.
However, there is nothing stopping you from inheriting every class from NSObject. The class is still there and it is especially useful if you are dealing with Obj-C APIs. In pure Swift, a root class is not necessary though.
One more note:
Swift classes doesn't run on top of Obj-C; they are not translated into Obj-C behind the scenes. They are just compiled by the same compiler which allows them to interoperate with each other. That's really important to understand. That's why #objc must be sometimes added to provide consistency with Obj-C protocols/classes.

Objective-C Private Method Dilemma

I'm aware that Objective-C doesn't support real private methods. What I'm currently doing to declare 'private' methods is adding the following to class .m files:
#interface MyClass()
- (void) privateMethodName;
#end
The Problem:
If I now add a subclass, and want to use this 'private' method, I can't! I get the error:
Receiver type 'SubClassName' for instance message does not declare a
method with selector 'privateMethodName'
So, if I don't want non-subclasses to be able to access this method, but do want subclasses to be able to, what can I do? What is the best/proper way of achieving my goal?
You could separate the "protected" interface from the public one. In the primary header, just declare the public methods:
MyMagicThingy.h:
#interface MyMagicThingy: NSObject
- (void) publicMethod;
#end
Then, have an additional header with protected methods:
MyMagicThingy+Protected.h:
#import "MyMagicThingy.h"
#interface MyMagicThingy (Protected)
- (void) protectedMethods;
#end
You cannot have "real" private/protected/public methods in Objective C (as in: the compiler will enforce access rules. All methods are public). You have to go with a convention.
What you describe is really a protected method. One approach to overcome this: Ivars can be declared #public, #protected, or #private. You could declare a protected helper instance to restrict access to derived instances, which then calls back through the object which holds it.
Another alternative in some cases would be to make the subclasses write to an interface, then keep your implementation private.
Sometimes, you just have to document "don't do this, unless you are not a subclass" because it's not part of the language. In this mindset, a separate header which declares a category of protected methods is one of my favorite. It's pretty well hidden from clients, but can be made visible to subclasses by explicit inclusion -- Dirk provided an example of this at the same time, check it out.
Lastly, if you're comfortable with ObjC++, C++ offers this control, so you can mix modes and visibility quite freely.
First and foremost
You can't get anyone to not being able to call any method that is implemented on an object in Objective-C (at least not without burning through several dozen razors making Yaks less weatherproof).
Just don't call methods that are not declared in public header files, as a convention (this is, what you're already doing).
Second
The word public in the above paragraph does the trick:
In Objective-C (at least in its current incarnation), a class's interface can be defined over any number of header files using the technique you just described in your post: Class continuations.
One such example of an Apple framework class doing that would be UIGestureRecognizer with its separate subclassing header UIGestureRecognizerSubclass.h.
PS:
The error you are seeing reeks of using ARC so your runtime is definitely recent enough to even use multiple implementation files for that.

objective c categories and inheritance

If a method is defined in both a class and a category on that class, it is undefined which implementation will be called.
But how does this interact with inheritance? Specifically:
Given a superclass category method and a regular method in the subclass, is it guaranteed that the subclass implementation will win when called on a member of the subclass?
Given a superclass regular method and a subclass category method trying to override it, is it guaranteed that the subclass category implementation will win when called on a member of the subclass?
Given a superclass category method and a subclass category method, is it guaranteed that the subclass category method will win when called on a member of the subclass?
Lets just put it this way. Don't override methods using categories, period, ever, end of answer.
If a method is defined in both a class and a category on that class,
it is undefined which implementation will be called.
That is incorrect; the category method will always win. What won't work, though, is if you have multiple categories that implement the same method, then the "which one wins" is undefined.
It is generally "last loaded wins", but that really isn't a hard rule, either.
Note that since many classes will internally have their implementation dividing across categories for code organization purposes, you can't rely on the first rule anyway.
In short, what Joshua said; Do not override methods using categories.
Beyond the inheritance reasons, you are also viciously breaking encapsulation when you do so. It isn't that a category based implementation overrides an existing method, it entirely replaces it. Thus, if you don't reproduce every last internal implementation detail, including bugs, your replacement won't quite work right and debugging it will be hard.
From what I test
Given a superclass category method and a regular method in the
subclass, is it guaranteed that the subclass implementation will win
when called on a member of the subclass? => subclass wins
Given a superclass regular method and a subclass category method
trying to override it, is it guaranteed that the subclass category
implementation will win when called on a member of the subclass? =>
subclass category wins
Given a superclass category method and a subclass category method,
is it guaranteed that the subclass category method will win when
called on a member of the subclass? => subclass category wins
Take a look at the Test category and subclass

Is it good style to declare methods in .h when they're intended to be overwritten by subclass?

I have a class which is intended to be abstract. This means: When someone subclasses it, a few methods MUST be overwritten.
But on the other hand, those methods are not intended to be called manually from anywhere except inside the abstract class (the superclass of the subclass).
Must I declare these methods in .h anyways or can I just add comments in .h which say "you must overwrite -foo and -bar"? Or is there a better pattern to make abstract methods?
Related: Is there a way to create an abstract class in Objective C?
Objective-C doesn't actually have a way to declare a class as abstract. From Apple's Docs:
Abstract Classes
Some classes are designed only or
primarily so that other classes can
inherit from them. These abstract
classes group methods and instance
variables that can be used by a number
of different subclasses into a common
definition. The abstract class is
typically incomplete by itself, but
contains useful code that reduces the
implementation burden of its
subclasses. (Because abstract classes
must have subclasses to be useful,
they’re sometimes also called abstract
superclasses.)
Unlike some other languages,
Objective-C does not have syntax to
mark classes as abstract, nor does it
prevent you from creating an instance
of an abstract class.
The NSObject class is the canonical
example of an abstract class in Cocoa.
You never use instances of the
NSObject class in an application—it
wouldn’t be good for anything; it
would be a generic object with the
ability to do nothing in particular.
The NSView class, on the other hand,
provides an example of an abstract
class instances of which you might
occasionally use directly.
Abstract classes often contain code
that helps define the structure of an
application. When you create
subclasses of these classes, instances
of your new classes fit effortlessly
into the application structure and
work automatically with other objects.
So to answer your question, yes, you need to place the method signature in the header, and should implement the method in the base class such that it generates an error if called, like the related question's answer states.
You can also use a protocol to force classes to implement certain methods.
However you choose to implement the base class, clearly document in the header, as well as in your documentation, exactly what the class assumes and how to go about sub-classing it correctly.
Whenever possible write your code so that improper implementations fail to compile. If you cannot do that then you should try to generate a runtime error (at the very least in a debug build) if the subclass is not written correctly. Do not rely on comments because people will not read them.
You must declare your "protected" and "abstract" methods in a header file, but you can use separate categories to clearly indicate their purpose and intended use.
#interface MyBaseClass : NSObject {
}
- (void)foo;
#end
#interface MyBaseClass(ProtectedMethods)
- (void)bar;
#end
#interface MyBaseClass(AbstractMethods) // Subclasses must implement
- (void)internalBar;
#end
You can put everything in a single header, or you could put your protected and abstract declarations in a separate "protected" header, say MyClassProtected.h, meant to be included only by your subclass implementations. It depends on how badly you want "hide" your protected methods.
Your base class can log, assert, or throw when an abstract/pure-virtual method is called.
As other people have said, Objective-C does not support pure virtual classes.
You can enforce pure virtual behaviour at runtime though. The cleanest way to do this is by using the Objective-C runtime's _cmd and NSObject's -doesNotRecognizeSelector:
- (void)iMustBeImplementedInaSubclass;
{
[self doesNotRecognizeSelector:_cmd]; // Pure virtual
}
As ben says you are probably better served by using a protocol to get your API design right.