Swift super initializer - swift

In Swift, super's initializer should be called after all properties of the current class have been initialized. This is however not done for Objective-C init, where super init is called first before initializing properties in the current class.
What issues is Swift trying to prevent by enforcing this? Why is Objective-C able to avoid the issues Swift is trying to prevent?

What issues is Swift trying to prevent by enforcing this?
This is a great question, and Objective-C did not avoid it.
The problem is that while you're inside an initializer method, the object is technically in a partially constructed state. Bryan's post is a great (albeit contrived) example of why. The general issue is that if a super class's initializer invokes a method, a subclass may have overridden this method. That, in and of itself, is not a bad thing. The problem arises if the overridden method assumes that the object is totally constructed.
However, since the object is still in the midst of invoking the initializers, that is not the case. The object is not wholly constructed until the call to [super init] returns and the class of the object executes any of its initialization code.
There's a related problem with dealloc methods: if you invoke methods inside your -dealloc method, those methods may assume that the object is wholly constructed, when in fact it may be partially deconstructed. This isn't as big of a deal under ARC, but it can still lead to some very subtle bugs.
With Swift, the decision was made to avoid these class of problems by enforcing this rule:
By the time you decide to call super, the calling class must have finished any class-specific initialization.
A variant of this rule is:
You may not invoke methods until after you have called super's initializer.
With this rule, you will never run into the problem described above.

ObjC does not avoid anything.
For this ObjC code, it crashed because parent class is trying to access ivar from child class. It can be detected/avoid if the Swift rule is used. i.e. initialize all members before [super init]
#interface Parent : NSObject
#property (readonly) int value;
#end
#implementation Parent
- (id)init {
self = [super init];
if (self) {
NSLog(#"%d", self.value); // call a method, which can be overrided by child class
}
return self;
}
- (int)value {
return 42;
}
#end
#interface Child : Parent
#end
#implementation Child {
int *_valuePtr;
}
- (id)init {
self = [super init]; // call self.value
if (self) {
// to avoid crash, move this line before [super init], but it may have other undesired effect. e.g. when [super init] return another instance
_valuePtr = calloc(sizeof(int), 1);
}
return self;
}
- (void)dealloc {
free(_valuePtr);
}
- (int)value {
return *_valuePtr;
}
- (void)setValue:(int)value {
*_valuePtr = value;
}
#end

Related

Using class extensions in xcode 4.4

Since xcode 4.4 you don't need to #synthesize properties anymore (see here), the compiler does it for you. So, why does the compiler complain
use of the undeclared identifier _aVar
in my viewDidLoad method of ViewControllerSubclass:
#interface ViewController : UIViewController
#property (assign, nonatomic) int aVar;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.aVar = 5;
NSLog(#"Super value: %d", _aVar);
}
#end
#interface ViewControllerSubclass : ViewController
#end
#interface ViewControllerSubclass ()
#property (assign, nonatomic) int aVar;
#end
#implementation ViewControllerSubclass
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"Subclass value: %d", _aVar);
}
#end
If I move everything to the one file instead of 4 separate files for the respective interfaces and implementations, the compiler instead complains that _aVar is private. But _aVar should have been automatically synthesized in my ViewControllerSubclass.
Still keeping everything in 1 file, if I move the initial property declaration to a class extension:
#interface ViewController ()
#property (assign, nonatomic) int aVar;
#end
The build still fails saying that _aVar is private.
If I go back to the 4 file setup for the respective interfaces and implementations xcode builds without even a warning.
If I then run the code:
[[[ViewControllerSubclass alloc] init] view];
the log statements in the above examples print out the following:
Super value: 0
Subclass value: 5
It makes sense that NSLog(#"Super value: %d", _aVar); produced a result of 0 because this variable is supposed to be private to the superclass. But then, why does NSLog(#"Subclass value: %d", _aVar); produce a result of 5??
This is all very odd.
You are confusing several different issues, and I'm somewhat confused when you talk about jumping between files and you don't specify where your errors are happening.
Anyway, there is the issue of instance variable visibility. If you declare your iVars within the interface scope, they are, by default, protected.
#interface Foo : NSObject {
int protectedInt;
#private
int privateInt;
#public
int publicInt;
}
#end
When you synthesize iVars, the instance variables themselves are private, unless you explicitly specify them.
Methods will always fire on the most derived implementation.
Now, when you call this...
[[[ViewControllerSubclass alloc] init] view];
You will allocate a subclass, initialize, and cause the view to be loaded. This code will execute...
#implementation ViewControllerSubclass
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"Subclass value: %d", _aVar);
}
#end
The first thing it does is call the base class implementation...
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.aVar = 5;
NSLog(#"Super value: %d", _aVar);
}
#end
Of course, it calls super, but that part's not important here. The next line assigns 5 to self.iVar. But, which iVar? It calls the property setter method on this object. What type is this instance? It's a ViewControllerSubclass. Since you have given both your base class and its subclass the same name (and declared the property as part of the class extension), they each have their own private-scope instance variable .
However, a method is called on the most derived implementation. Thus, self.iVar will set the instance variable of the subclass. The instance variable for the base class remains unchanged.
When you NSLog the value, you are accessing the private instance variable of the base class, which has not been changed.
Now, after the base class viewDidLoad finishes, we get the code running for the subclass. It logs the value of its private instance variable, which was changed as a result of the base class calling the property setter. So, it will now print it's value, which is 5.
When you make the superclass declaration public, the compiler won't attempt to re-synthesize the property; it assumes that's been taken care of in the superclass. Thus, _aVar is not in scope anywhere in the subclass. It's private anyway, so even when you put them all in the same file that's why you see those errors.
However when you make the superclass property declaration inside the class extension, the compiler will auto-synthesize the property for both the superclass and the subclass. This ends up with both classes having private instance variables _aVar (with two distinct addresses). However, when the superclass viewDidLoad method sets the property, the method invokes the subclass's accessors, which set the value of the subclass's private _aVar variable, and not the superclass's. So that explains why you see the superclass value not changing.
Hope this helps!
I just tested your setup and could replicate your error. I came to the following conclusion:
You need to declare your #property in a .h file. If you want a private variable, declare it in .m in the category #interface (the one with the parentheses).

How does respondsToSelector behave when there is a delegate present?

I recently tried to subclass UITextField and set the delegate to myself (found this trying ti solve my problem: http://www.cocoabuilder.com/archive/cocoa/241465-iphone-why-can-a-uitextfield-be-its-own-delegate.html)
#interface MyObject :UITextField <UITextFieldDelegate>
#end
#implementation MyObject
-(id) initWithFrame:(CGRect) frame
{
if((self=[super initWithFrame:frame]))
{
self.delegate=self;
}
return self;
}
-(BOOL) respondsToSelector:(SEL)selector
{
NSLog(#"responds to selector");
return [super respondsToSelector:selector];
}
// Implement all the missing methods
#end
Calling a method defined on the interface results in an infinite recursion. I don't see anything in the Apple docs that defines how respondsToSelector is supposed to behave in the presence of a delegate.
The docs for respondsToSelector states the following:
You cannot test whether an object
inherits a method from its superclass
by sending respondsToSelector: to the
object using the super keyword. [..]
Therefore, sending respondsToSelector:
to super is equivalent to sending it
to self. Instead, you must invoke the
NSObject class method
instancesRespondToSelector: directly
on the object’s superclass
It seems that this could be the cause for your recursion problem. I don't know if the delegate stuff is even related. Just a guess though.

Subclassed UIView from NIB File not typed to subclass

I have a NIB file, with some class (SomeClassView : UIView) set as the custom class of the top level view of the NIB. SomeClass has IBOutlets that I use to hookup subviews of SomeClass that I lay out in Interface Builder.
I instantiate SomeClass like this:
- (id)initWithFrame:(CGRect)frame {
self = [[[[NSBundle mainBundle] loadNibNamed:#"SomeClassView" owner:nil options:nil] objectAtIndex:0] retain];
// "SomeClassView" is also the name of the nib
if (self != nil) {
self.frame = frame;
}
return self;
}
Now say I subclass SomeClass with SubClassView. I add a method to SubClassView called -(void)foo:
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self != nil) {
[self foo];
}
return self;
}
At this point I get a runtime error: * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[SomeClassView foo:]: unrecognized selector sent to instance 0xAAAAAA'
It seems as though "self" within initWithFrame of SubClassView is still set to the super, SomeClassView. A quick hack fix to work around this is to change the isa pointer within SubClassView initWithFrame:
- (id)initWithFrame:(CGRect)frame {
Class prevClass = [self class];
self = [super initWithFrame:frame];
if (self != nil) {
isa = prevClass;
[self foo]; // works now
}
}
It's not an ideal workaround, since I have to update isa each time I subclass, or there could even be different init methods which I'll also have to update.
1) Ideally, is there an easy way to fix this, purely by code? Maybe with the way I'm setting self = the loaded nib?
2) Is there an alternative architecture that works better for what I'm trying to do? One example is to set the owner to self, but then you'd have to set all the property/outlet mappings manually.
Swapping isa pointers is a problem if your subclasses have instance variables other than those declared in SomeClassView. Note that your nib file has an object of type SomeClassView, which means that, upon loading the nib file, the nib loader will allocate an object of that type and unmarshall it from the nib file. Changing the isa pointer to [SubViewClass class] temporarily won’t make it an object of type SubViewClass per se since what the nib loader allocates is a SomeClassView object.
That said, I don’t think there’s a reliable and automatic way to use nib files containing objects whose types need to be changed upon nib loading.
What you could do is to have your SomeClassView objects declare a delegate conforming to some protocol. This protocol would define methods for behaviour in SomeClassView that can potentially be extended. For instance,
#protocol SomeClassViewDelegate
#optional
- (void)someClassViewDidAwakeFromNib:(SomeClassView *)someClassView;
#end
Instead of subclassing SomeClassView, you’d have arbitrary objects performing whatever custom behaviour you currently have in SubClassView. For instance,
#interface SubClassViewBehaviour : NSObject <SomeClassViewDelegate>
…
#end
#implementation SubClassViewBehaviour
- (void)someClassViewDidAwakeFromNib:(SomeClassView *)someClassView {
// whatever behaviour is currently in -[SubClassView foo]
}
#end
A SubClassViewBehaviour object would be created in code and set as the nib file’s owner upon loading the nib file, or any other IB proxy object for that matter. SomeClassView would have a delegate outlet connected to file’s owner/proxy object, and it’d invoke the delegate methods in the appropriate places. For instance,
#implementation SomeClassView
- (void)awakeFromNib {
SEL didAwakeFromNib = #selector(someClassViewDidAwakeFromNib:);
if ([[self delegate] respondsToSelector:didAwakeFromNib]) {
[[self delegate] performSelector:didAwakeFromNib withObject:self];
}
}
#end
One further remark: your code currently leaks a view object since two objects are being instantiated: one via +alloc in your code and another one via nib loading. You’re assigning the latter to self, hence the one created via +alloc is leaking. Also, I believe you’ve missed a call to super in your third code snippet.
Rather than do this from within the subclass itself why not ensure it is the right class when you first instantiate it from outside the class:
SubClass *instance = [[SubClass alloc] initWithNibName:#"SomeClassView" bundle:nil];

Memory Management in Objective-C

I wanna ask if I allocated an instance variable for private use in that class, should i release it immediately on site, or i can depend on dealloc function. (because maybe i will need it on other function) ?
//Player.h
#interface Player : NSObject
{
NSMutableArray * objectArray;
}
- (void)awake;
- (void)add;
#end
//Player.m
#implementation Player : NSObject
{
-(id) init {
self = [super init];
if (self != nil ){
[self awake];
[self add];
}
return self;
}
- (void) awake {
objectArray = [[NSMutableArray alloc] init]; //is it cause leakage?
[objectArray addObject:#"foobar"];
}
- (void) add {
[objectArray addObject:#"foobar2"];
}
- (void) dealloc {
[objectArray release];
[super dealloc];
}
}
#end
or should i using property to set the objectArray iVar?
//Player.h
#interface Player : NSObject
{
NSMutableArray * objectArray;
}
#property (nonatomic,retain)NSMutableArray* objectArray;
- (void)awake;
- (void)add;
#end
//Player.m
#implementation Player : NSObject
{
-(id) init {
self = [super init];
if (self != nil ){
[self awake];
[self add];
}
return self;
}
- (void) awake {
self.objectArray = [[NSMutableArray alloc] init autorelease]; //cause leakage?
[objectArray addObject:#"foobar"];
}
- (void) add {
[objectArray addObject:#"foobar2"];
}
- (void) dealloc {
[objectArray release];
[super dealloc];
}
}
#end
if both of them doesn't cause a leakage, what type should i use?
should i always set iVar property, and access iVar value with self even if i only want to use it in this class?
I like to take the stance that if the instance variable should not be visible outside of the class then it should not be implemented as a property. But it's a personal thing that other developers may not agree with.
Either way you would need to release the objectArray in your classes dealloc method - which is what you're currently doing.
However you need to be careful with your awake method - if it's invoked multiple times then objectArray is leaked. This is the downside of not using properties. A use of self.objectArray = [[NSMutableArray alloc] init] here would have released the previous object.
In my opinion, you should only declare properties in your header if other objects are allowed to use them. There is no good reason why you would provide an -add: method (as in your example) that adds something to your array while also providing a getter for your array so other objects can manipulate it directly. It's called encapsulation.
If you do want to have the benefits of generated getters/setters for your implementation file, you can always use a class continuation (a nameless category) inside your implementation file and include your property declarations there. That way you get real, auto-generated properties that are only visible to your class' implementation.
Personally, I wouldn't use any getter or setter methods in your example. Just allocate the NSArray in your -init and release it in -dealloc. If this -awake method of yours might be called multiple times, just add an [objectArray removeAllObjects] call and you're sure to have an empty array without worrying about memory management.
It is very likely that memory will leak in your first example because you are not sending release to the previously set instance variable (if it already existed).
This is why you should use property setters - they handle all of this stuff for you.
Also, since you are obtaining ownership of the instance variable through the property (which is defined with the retain keyword), you will definitely leak memory if you don't send the instance variable the -release message in your -dealloc method.
So the verdict is that you should use the second example, not the first.

How to initialize an NSObject's subclass on iPhone?

I want to write some methods in a class so that other classes can call these methods using [instance methodName:Parameter].
If the class is a subclass of UIViewController, I can use initWithNibName to initialize it. But I want to write the methods in an NSObject's subclass, how can I initialize it?
iphony is correct, but he or she doesn't say that you need to write the init method yourself. Your init method should generally look something like this:
- (id) init
{
if (self = [super init])
{
myMember1 = 0; // do your own initialisation here
myMember2 = 0;
}
return self;
}
Although the apple documentation says
The init method defined in the NSObject class does no initialization; it simply returns self.
and one can just be tempted to write
- (id) init
{
myMember1 = 0; // do your own initialisation here
myMember2 = 0;
return self;
}
this is WRONG and not following what is explicitly stated in documentation:
In a custom implementation of this (init) method, you must invoke super’s
designated initializer then initialize and return the new object.
MUST. Not should, could, ought to, etc.
You should not assume NSObject's init does not change in future; nor the superclass from which your custom class derives.
I find this may work:
TheClass *newObject = [[TheClass alloc] init];
//do something here
[newObject release];