Is it an acceptable pattern for an init method to return an object of a different type? - objective-c

I'm working on bugfixes for some existing objective-c code and came across something I thought strange:
#interface ClassA : UIView
...
static ClassA* oldSelf = nil;
#implementation
- (id)initWithFrame:(CGRect)frame {
oldSelf = self;
self = [[ClassB alloc] initWithFrame:(CGRect)frame]; // xcode warns: Incompatible pointer types assigning to "ClassA *" from "ClassB *"
// ^^^^^^ Is this ok?
[oldSelf release];
return self;
}
#interface ClassB : UIView
...
#implementation
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
return self;
}
This whole thing is wrapped up into a static library. The public gets the lib.a file and ClassA.h
In code using the library, This occurs:
#import "ClassA.h"
...
// useage
ClassA *myA = [[ClassA alloc] initiWithFrame:CGRectMake(0,0,100,100)];
...
So we got an initializer for ClassA that actually returns an unrelated class. ClassA and ClassB respond to the same messages so it compiles and runs. Seems like ClassA is being used to obscure some features exposed in ClassB?
I'm curious if this is acceptable behavior, and if it's a known pattern, what is it called? Are there any side effects to this setup?
=========================================================
Thanks for everyone's answers! I think I've got it... in short, not a normal pattern, and not exactly a good idea
Kind of like a "class cluster"(abstract factory), but not quite, because a common abstract class should be returned. And since the code doesn't seem to ever intend to return anything but a ClassB object, probably not what the original author was thinking.
More like a proxy, but implemented wrong. ClassA should hold a private instance of ClassB and pass messages between the two.
=========================================================
Edited: added "oldSelf" parts...
Edited: added static library details...
Edited: added a blurb about the accepted answer...

The major disadvantage I see here is: a user of ClassA would expect that an object he just created via [[ClassA alloc] initWithFrame:...] returns YES for [object isKindOfClass:[ClassA class].
This might also lead to errors when using things like NSInvocation, because the wrong class would be used to determine the method signature, though I am not sure about that.
Due to Objective-Cs dynamic nature, this will, as you described, work, but may be confusing to use and i would strongly discourage anyone from using this pattern.
As pilavdzice said, the "right" alternative to this would be to have both ClassAand ClassB inherit from another class (an abstact superclass) which then in its initializer decides what concrete subclass to use. Good examples of this pattern, called class clusters, are NSString, NSArray and NSDictionary which all return objects of various subclasses based on how you initialize them, which is also the reason you can not subclass those directly without some effort.

It's not an unreasonable thing to do in all cases, but it's hard to say whether it's a good idea in the situation you describe. Two examples where it might be fine:
The initializer returns an instance of a more specialized subclass. For example, you might choose different implementations of a data structure depending on the number of items being stored.
The initializer returns some sort of proxy object.
Your code does seem a bit odd. At the very least, I'd expect to see a cast as a signal (both to the compiler and to future programmers) that the author knew what he was doing. A comment explaining the reason for returning a different type of object wouldn't hurt, either. Ideally, ClassB should be a subclass of ClassA since it's expected to provide the same interface.

Class clusters are implemented in this way, sort-of. A related technique, isa-swizzling can be used to implement a sort of state machine. It does require the same ivar layout to work. In terms of side effects, I believe that it may break KVO; but someone may correct me on that point.

It's certainly not common in user code to return an unrelated class, however it is common in some of Apple's frameworks to return a more specific version of a class with the same public interface.
Apple's Cocoa Fundamentals discusses in some amount of detail the fact that objects such as NSArray and NSNumber may return a different object than the class you are asking for.

That isn't a pattern I know of.
If I am understanding this correctly, the normal way to do this would be to have both classes inherit from the same abstract base class.

As #alan duncun notes, this technique is called a class cluster and is somewhat common. But your implementation is slightly incorrect. You should never return a incompatible type. In your example, ClassB should inherit from ClassA.

Well this is somewhat how NSScanner is implemented.
This way the inner class is not exposed and can not be misused. ClassB can not be initialized somewhere else other than in the implementation file of ClassA.
This makes sense if you have multiple inner classes and your initializer somehow decides which class is actually needed.
I don't see any advantages if you only use one inner class.

Related

Objective-C - Effective Subclassing of Cocoa Class Clusters

I have an object that used to be an NSMutableSet but needed some more stuff attached to it. The obvious (and obviously not supported) thing to do is to subclass NSMutableSet and tack on the two additional properties. Since NSMutableSet, like basically all Cocoa data structures, is a class cluster I cannot subclass it in the usual way, since the super class just throws exceptions. This led me down several paths.
The first path was to create sort of a composite object that declared itself as a subclass of NSMutableSet but really just forwarded the invocations to an internal NSMutableSet. I didn't want to have to implement every method on NSMutableSet, so I thought forwardInvocation: would be a good way to accomplish my mission. Unfortunately, the abstract class of NSMutableSet implements all of the methods on the interface and their implementations throw exceptions, so I was never getting to the point where I could forward an invocation.
The second path was to subclass NSProxy and forward the invocation from there. This solution falls short in that I need to copy the interface of NSMutableSet over unless there's a way to declare "this class implements this interface" that I don't know about (this could very well be the solution).
The third path was to create a category on NSMutableSet and import it just for the class that needs to use it but that falls short since you cannot add non-dynamic properties via a category. That led me to using associated objects in a category. I'm willing to admit that that is the correct solution for this use case, but I wish it weren't since it's kind of clunky. It's doubly clunky since the properties I'm adding are primitive so I'll have to wrap and unwrap them when setting and getting the association (unless there's a way to associate primitives which I'm unfamiliar with).
Essentially, what I would like is something that behaves functionally as a subclass of NSMutableSet (and all class clusters) but cannot figure out the best approach. Thanks!
Trying to subclass Cocoa class clusters will just create an awful lot of hurt. It may seem a good idea, but you will forever run into problems.
Just create an NSObject with an NSMutableSet as the first member object.
Subclassing Cocoa class cluster is kind of discouraged. Not without reasons. Please do not enter this crashy world.
Either of your solutions will work. I've successfully used the first path with NSArray and NSDictionary, so I believe it should work fine for NSMutableSet as well. Just remember that you need to override not only forwardInvocation:, but a few of other methods as well. Please consult Surrogate Objects sections of Apple docs:
Although forwarding mimics inheritance, the NSObject class never confuses the two. Methods like respondsToSelector: and isKindOfClass: look only at the inheritance hierarchy, never at the forwarding chain.
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtForwarding.html
In my case, I've overridden:
conformsToProtocol:
isKindOfClass:
isMemberOfClass:
respondsToSelector:
instancesRespondToSelector:
forwardInvocation:
methodSignatureForSelector:
instanceMethodSignatureForSelector:
from which isKindOfClass:, conformsToProtocol: and respondsToSelector: are definitely crucial.
I've also used the third path with good results, but I admit the associated objects API is clunky.
First, gnasher729 is correct. Don't subclass class clusters. Just don't do it. Can you do it? If I tell you that you can't, will it help you convince yourself that you shouldn't? I can lie if it helps you make good choices.
But in all seriousness, it is almost always meaningless as well. Is your subclass really a specific kind of set? Or is it really kind of like a set. Consider NSAttributedString. It isn't a kind of string, it has-a string. This is almost always better.
And also, class clusters happen to be a royal pain to subclass.
That said, adding associated values onto a data structure, as you've already discovered, is generally just fine, because what you really want is "hey, I have some data that needs to go along with this other data." Wrapping has gotten so easy that it shouldn't really slow you down. See https://stackoverflow.com/a/14918158/97337:
objc_setAssociatedObject(self, animatingKey, #(value), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
And with "one weird trick", you can make this really easy:
#interface NSObject (BoolVal)
#property (nonatomic, readwrite, assign) BOOL boolVal;
#end
#implementation NSObject (BoolVal)
- (BOOL)boolVal {
return [objc_getAssociatedObject(self, _cmd) boolValue];
}
- (void)setBoolVal:(BOOL)value {
objc_setAssociatedObject(self, #selector(boolVal), #(value), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#end
But I'd still come back to the question of whether this is really a kind of set (rather than just like a set), and whether it really needs to respond to every message that can be sent to a set. As with NSAttributedString, your real needs are often much smaller than that in practice, and wrapping the handful of methods you need is often worth the simplicity and control.
For completeness, let's look at your first path:
create sort of a composite object that declared itself as a subclass of NSMutableSet but really just forwarded the invocations to an internal NSMutableSet
Can you subclass an NSMutableSet? Yes, but should you? The documentation for NSMutableSet says:
Subclassing Notes
There should be little need of subclassing. If you need to customize behavior, it is often better to consider composition instead of subclassing.
So weigh that up and if you want to subclass refer again to the documentation:
Methods to Override
In a subclass, you must override both of its primitive methods:
addObject:
removeObject:
You must also override the primitive methods of the NSSet class.
And looking at the NSSet class documentation we find its primitive methods are:
Methods to Override
In a subclass, you must override all of its primitive methods:
count
member:
objectEnumerator
That's it, 5 methods.
You can define your own class as a subclass of NSMutableSet, add an instance variable which is an instance of NSMutableSet, implement 5 methods and redirect them to the set instance, add whatever init methods you wish, and then add your additional properties.
If performance is of concern then the tradeoff is between redirecting those five methods and accessing associated objects for your additional properties. You'll need to profile to work that out, but if and only if performance becomes an issue.

How should I be using class variables in Objective-C?

This has been bugging me for a long time, and I have tried to look it up many times.
When I first began learning Objective-C, I remember looking into class variables. I saw many threads on stack overflow and elsewhere that basically said, "Objective-C doesn't support class variables like C does, but there are some workarounds."
Reading this made me shy away from using class variables, especially because I have read hundreds of times that global variables tarnish the elegance of OOP.
So I have a very open ended, opinionated, and conversational question:
Should I use class variables in objective C? Also, am I doing it right?
Here is my situation: I am making an app, and I set up a touch handling class to deal with all the input received from screen touches. The data is pretty useful, and I would like every single sprite to have access to it.
Since every object is a subclass of my GameObject class, I figure I just make a class variable, done like so:
header for GameObject class:
+(SSTouchHandler *)touchHandler;
+(void)setHandler:(SSTouchHandler *)handler;
implementation for GameObject class:
static SSTouchHandler *touchHandler = nil;
+(SSTouchHandler *)touchHandler
{
if (touchHandler)
return touchHandler;
else
return nil;
}
+(void)setHandler:(SSTouchHandler *)handler
{
touchHandler = handler;
}
Now, this works. This works beautifully.
I can refer to my handler with [GameObject touchHandler] from every place I need.
This is all I could ever want and more.
But should I use this method? Am I dirtying the beauty that is object oriented programming?
Is there a way I should touch up this process to make it work optimally?
Thanks for any and all input, I probably rambled a bit, I just don't want to proceed with a faulty game structure.
I saw many threads on stack overflow and elsewhere that basically
said, "Objective-C doesn't support class variables like C does, but
there are some workarounds.
"Class variables" make no sense in the context of C since C is not object oriented.
So I have a very open ended, opinionated, and conversational question:
Should I use class variables in objective C? Also, am I doing it
right?
This is more of a general OOP question than anything specific to Objective-C. The answer tends to be pretty subjective, but in general I'd say to avoid them unless you're trying to set a property of some sort that affects all instances of a class.
Here is my situation: I am making an app, and I set up a touch
handling class to deal with all the input received from screen
touches. The data is pretty useful, and I would like every single
sprite to have access to it.
It sounds to me like a better design pattern for this would be to pass the SSTouchHandler instance as a parameter to the initializer of the sprite objects that use it. e.g.:
#interface GameObject : NSObject
- (id)initWithTouchHandler:(SSTouchHandler *)handler;
#end
Now, if you really want to use the same instance of SSTouchHandler for every GameObject, you have two options:
1) The controller/factory that creates the GameObject objects should create and keep a reference to a single instance of SSTouchHandler, and then initialize any new GameObject instances with it. For example:
#interface GameObjectController : NSObject
#property (nonatomic, strong, readonly) SSTouchHandler *touchHandler;
- (GameObject *)newGameObject;
#end
#implementation
- (id)init
{
if ((self = [super init])) {
_touchHandler = [[SSTouchHandler alloc] init];
}
return self;
}
- (GameObject *)newGameObject
{
return [[GameObject alloc] initWithTouchHandler:self.touchHandler];
}
#end
2) You could make SSTouchHandler a shared singleton and call methods on the shared instance directly from the implementation of GameObject. However, shared singletons are discouraged in OOP because they hide dependencies and make it difficult to unit test code that depends on them. You shouldn't go down this route unless you deem it absolutely necessary.
implementation for GameObject class: ...
If you decide that the patterns above aren't suitable for your use case (and that sometimes does happen), yes that is essentially how you would implement class properties in Objective-C. One thing:
if (touchHandler)
return touchHandler;
else
return nil;
This is not necessary, you can just return touchHandler since it will be nil anyways if not set.
If it works, you're done. I think there are some improvements, though. First, you might like to use an instance var here: it's not more complicated, but it allows some flexibility in the future (e.g. if you want to make two views side by side). Also, using a bare pointer is not so good; the class here does not own the pointer, and it can be left dangling! Defining the touchHandler as a property (also an instance var) takes care of that problem.

AbstractFactory pattern in objective-c

I'm just trying to learn objectives-c.
I've seen wikipedia example for AbstractFactory pattern, across different languages.
Here's the Button definition:
#protocol Button
- (void)paint;
#end
#interface WinButton : NSObject <Button>
#end
Here's a factory:
#implementation WinFactory
- (id)createButton {
return [[[WinButton alloc] init] autorelease];
}
#end
As far as I kwnow, obj-c's id keyword should be something like C#'s var or C++11's auto,
right?
So I my question is:
why let the factory return a generic object of a not specified type?
Is this an error (that let factory return something other that is not a Button) or is there any reason to do that?
I'd write a factory this way:
#implementation WinFactory
- (id<Button>)createButton {
return [[[WinButton alloc] init] autorelease];
}
#end
am I wrong?
why let the factory return a generic object of a not specified type?
In many cases where you see id returned, it is because they are not consistently typed (really abstract objects), or it is because an implicit upcast would have been introduced.
Is this an error (that let factory return something other that is not a Button) or is there any reason to do that?
It is not an error. Of course, you should not return a type which does not match.
I'd write a factory this way:… am I wrong?
#implementation WinFactory
- (id<Button>)createButton {
return [[[WinButton alloc] init] autorelease];
}
#end
The big gotcha in this scenario is that ObjC is quite loosely typed, and you should strive to ensure all selectors' parameters and return types match. That is to say, every createButton in all your translations should all return the same type and have the same types for parameters. Sometimes you will have to choose a more descriptive name in order to avoid ambiguity for the compiler.
That ought to explain why +[NSString string] returns id -- if it returned NSString, then +[NSMutableString string] could be a source of warnings. This is because the compiler can have a difficult (impossible) time matching a method declaration to a dynamic instance. That may also help you understand the 'wordy' naming of selectors, such as convenience constructors which also contain the type in the method (e.g. +[NSDictionary dictionaryWithObject:] as opposed to simply +[NSDictionary withObject:]).
But to get to your question: id<Button> or NSObject<Button>* or some other qualified type is just fine -- as long as you can live with that common method signature. You're introducing type-qualification, which helps the compiler help you.
The more correct return type here would be :
- (id<Button>)createButton;
This means that the returned type is an object that conforms to the <Button> protocol. I may fix up the WP page just to be a little more clear. The <Button> protocol should also inherit from the <NSObject> protocol for completeness (and to simplify actual usage).
Note that the Abstract Factory pattern is somewhat unusual in ObjC. I'm trying to think of a case where it's used in UIKit or Foundation. It's more common for the class to handle this internally (such as in NSNumber) and is called a class cluster.
Be very careful of trying to code in a C++ or C# style in ObjC. ObjC is not a static language, and the patterns used are often quite different. (I'm not saying that AF is a static pattern. It could be used quite well in ObjC. I'm just saying that the fact that you're looking at it while trying to learn ObjC means that you may be approaching it backwards, learning "how do I do this C++ in ObjC" rather than learning "how do I develop in ObjC.")
Objective-C has the concept of class clusters, which are abstract factories.
See this answer.

How can I prevent a method from being wrongly overridden

How can I prevent a method from getting overridden in a subclass, missing a call to its superclass' implementation within?.
I know calling [super methodName]; will solve my problem sometimes.
But if somebody else was to use my parent class and overrode my method, accidentally missing to call super, what can I do?
Some more explanations:
I create a viewcontroller VC1 which has a method -(void)indexDidChange:(int)index { }. I write some actions there which I need to perform every time. and I subclass this viewcontroller named as SVC1 in it I need -(void)indexDidChange:(int)index { } for doing some other actions but at the same time the VC1 -(void)indexDidChange:(int)index { } action also need to perform. So I need to call like,
-(void)indexDidChange:(int)index {
[super indexDidChange:index];
}
So I decide to change VC1 function like,
-(void)indexDidChange:(int)index {
[self currentIndexDidChange:(int)index];
}
-(void)currentIndexDidChange:(int)index { }
And I need -(void)currentIndexDidChange:(int)index { } to override and prevent -(void)indexDidChange:(int)index { } from overriding.
Is it possible?
Edit: After OP rephrased the question it is clear that OP is actually NOT looking for final methods, despite the questions initial phrasing, which implied just this.
New (updated) answer to OP's question on method overriding safety:
According to your rephrased question you are not looking for protecting a method from being overridden at all, but rather worried about one of your subclasses overriding a method and accidently missing to include a call to super in its new implementation.
This however is a fairly common and widespread issue and something you're dealing with on a daily basis, without paying much attention to it.
Every Objective-C programmer is familiar with the following method, right?
- (void)dealloc {
[iVar release], iVar = nil;
[super dealloc]; //skipping this call to super is fatal!
}
And we al know that skipping the [super dealloc]; makes things get uncomfortable. (afaik the clang compiler issues a warning if dealloc lacks the call to super, …pretty handy.)
Despite the fact that a bad overriding of this method can have fatal consequences Apple did not choose to put any kind of security system in place here.
Instead Apple did this (as done with any other method requiring calls to super):
Add a note to the method's documentation:
After performing the class-specific
deallocation, the subclass method
should incorporate superclass versions
of dealloc through a message to
super
Expect you, the programmer, to be a grown-up and responsible for what you do. And for playing by the rules (as defined by the documentation).
Keep in mind that - (void)dealloc is by no means an exception. There are dozens and dozens of methods of this type in Cocoa. (Take just about any derivative of - (id)init, most of the KVO observing methods, etc. just to name a few.)
So what you should do is:
Write a good documentation for your
method. (better for your entire project, actually)
Add a big loud note to your method's documentation, explaining its rules.
Add a note to each of your subclasses' overridden method implementations, right above the line that's calling super, telling the reader/dev to look up documentation, when in doubt of the rules. (optional)
Code responsibly. Otherwise, you shouldn't be coding in first place. It's your customers who will suffer from it, eventually.
Old (pre-rephrasing) answer on archieving pseudo-final methods:
What you are asking for is the equivalent of a final function, as known from Java or C++.
Unlike Java or C++, however there are no final methods in Objective-C.
Depending on your situation there are solutions that might bring your at least near to what you're aiming for. All you'll get though is slightly better separation. You won't get any significant security from them. In Objective-C you cannot even be sure about the origin of your methods. Method swizzling allows you to exchange methods at will. With code injection you an even inject code into processes at runtime. All this is by design of Objective-C. Objective-C allows you to saw off the branch you're sitting on. Thus it demands you to act like a grown-up. As such there are no private methods either. If a method is proclaim private you as a dev are expected to behave accordingly.
Now to possible "solutions":
If only your super class if supposed to call the given (final) method anyway:
Then Macmade's solution of making your method a pseudo-private method would work quite well. The downside of hiding method declarations though is, that calling your hidden method from subclasses will give you a compiler warning, basically preventing*(sic!)* you from calling it. (It will not prevent you from calling the method though. It will only avoid you from doing so, by throwing compiler warnings.)
If subclasses however are expected to call the given (final) method:
Use a delegation pattern and by this only make those methods public that are allowed to be overridden.
To prevent overriding at all you could use the class cluster & abstract factory patterns, which hides your implementation classes and thus preventing overriding entirely. (Apple's NSArray, NSDictionary, NSSet classes do this)
However you might notice that with Objective-C lack of protection one usually can only choose between the two: openness, protectedness, not intermix them.
You can use categories in the implementation, so your methods aren't exposed in your header file.
MyClass.m
#interface MyClass( Private )
- ( void )myMethod;
#end
#implementation MyClass( Private )
- ( void )myMethod
{}
#end
#implementation MyClass
/* ... */
#end
If you don't declare your function in the ".h file" then its not listed, I think.

How does inheriting from NSObject work?

There are a couple of things about Objective-C that are confusing to me:
Firstly, in the objective-c guide, it is very clear that each class needs to call the init method of its subclass. It's a little bit unclear about whether or not a class that inherits directly from NSObject needs to call its init method. Is this the case? And if so, why is that?
Secondly, in the section about NSObject, there's this warning:
A class that doesn’t need to inherit any special behavior from another class should nevertheless be made a subclass of the NSObject class. Instances of the class must at least have the ability to behave like Objective-C objects at runtime. Inheriting this ability from the NSObject class is much simpler and much more reliable than reinventing it in a new class definition.
Does this mean that I need to specify that all objects inherit from NSObject explicitly? Or is this like Java/Python/C# where all classes are subtypes of NSObject? If not, is there any reason to make a root class other than NSObject?
1) Any time an object is allocated in Objective-C its memory is zeroed out, and must be initialized by a call to init. Subclasses of NSObject may have their own specialized init routines, and at the beginning of such they should call their superclass' init routine something like so:
self = [super init];
The idea being that all init routines eventually trickle up to NSObject's init.
2) You need to be explicit about the inheritance:
#instance myClass : NSObject { /*...*/ } #end
There is no reason to have a root class other than NSObject -- a lot of Objective-C relies heavily on this class, so trying to circumvent it will result in you needlessly shooting yourself in the foot.
Since it is possible to inherit from different root base classes, yes you must explicitly declare you inherit from NSObject when you make any new class (unless of course you are subclassing something else already, which itself in turn probably subclasses NSObject).
Almost never is there a need to make your own base class, nor would it be easy to do so.
Objective-C can have multiple root classes, so you need to be explicit about inheritance. IIRC NSProxy is another root class. You'll likely never want or need to create your own root class, but they do exist.
As for calling NSObject's init, it's part custom and part safety. NSObject's init may not do anything now, that's no guarantee that future behaviour won't change. Call init to be safe.
You need to call [super init] because there is code behind initializing that you dont have to write because it is written for you in NSObjects init, such as probably actual memory allocation etc.