Objective-C Why use init? - objective-c

I'm reading my first book on Objective-C [Programming in Objective-C 4th Edition], I'm midway through the book but one thing that bugs me, is that it didn't explain WHY we initialize objects.
I tried playing around with the with objects, for example allocating their memory but not initiating them and everything in the program works the same as before.
I'd appreciate some example explaining this, also.

The code within an init method is class specific - it performs whatever initialisation is required for that specific class. There are cases where a class does not need to perform any initialisation and thus removing this method call would have no effect.
However, by convention, you should always use init - what if someone were to add some required initialisation code to a class in the future?
See also:
alloc and init what do they actually do

To address you point of "everything works", the interesting thing about Objective-C is that alloc sets all instance variables to nil, and sending messages to nil doesn't do anything, it just returns nil, so in most of the cases you will not see a problem until you would try to do something illegal, consider a class like this
#interface MyObject : NSObject
#property (nonatomic, strong) NSString *string;
#end
#implementation MyObject
#end
Now if we'd just alloc it as:
MyObject *m = [MyObject alloc];
the instance variable _string, or property string would be nil, we could send different messages to it, like [string length] without any harm, since message to nil equals nil.
But say we then want to add this string to array, like
#[m.string]
Now you would get a exception, because NSArray cannot contain nil, only full blown objects. You can easily fix this by initializing your value inside MyObject.init.
Pretty contrived example, but hopefully shows the point of why everything doesn't break when you don't init :)

One of the main reasons why you should never use alloc's return value directly instead of using [[Class alloc] init]'s return value is that init might return a different object than alloc.
Apple's documentation mentions this:
Note: It’s possible for init to return a different object than was
created by alloc, so it’s best practice to nest the calls as shown.
Never initialize an object without reassigning any pointer to that
object. As an example, don’t do this:
NSObject *someObject = [NSObject alloc];
[someObject init];
If the call to init returns some other object, you’ll be left with a
pointer to the object that was originally allocated but never
initialized.
Source: http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/ProgrammingWithObjectiveC/WorkingwithObjects/WorkingwithObjects.html

Related

Circular references in Objective-C and clang

Why doesn't the static analyser detect circular references with blocks? I remember it used to do it when I had retains on my delegates instead of assign, pre-blocks introduction. I remember the nice little lines it used to draw on my code (i think...)
If I do this, without using weakSelf, I know I'm going to get a circular reference.
// Note 1: myObject is 'retained' by self.
// Note 2: myObject retains the block for the future
[self.myObject registerBlockOfCodeForFutureExectution:^{
[self doSomething];
}];
Sample Project Exploiting Issue
Now if I know this, and I'm a stupid human, then why doesn't my intelligent computer know this is bad and warn me that I'm being stupid?
There must be a logical reason why it can't detect it, and I want to know what that reason is.
This question is regarding clang and static analysis, please don't suggest how I fix circular references - I know how to do this.
If you use self inside of block it does not automatically mean that you get retain cycle. You get retain cycle only if life-time of block depends on life-time of self object. That may be the case if self has strong reference to myObject or some more complex dependencies are also possible (I assume that it indeed 'saves' block passed to a method, so you already have strong reference there).
So to have retain cycle in your example you need to have two following conditions met (neither of them follows from the code you posted), and compiler needs to be aware of them:
1. Life-time of myObject is tied to self - lets assume that self has strong reference to it
2. saveThisBlockInMyObject: retains block passed to it
I made a small sample that gives compiler warning about capturing self - to address 1st point I declared myObject as a strong property of some class:
#property (strong) MyTestClass* myObj;
...
self.myObj = [MyTestClass new];
For 2nd point I could not find a way to specify that method retains its argument (there're source annotations for returned values, but there's no relevant annotations for method parameters). But you declare block as a strong property of your test class, then compiler is happy to warn you about possible retain cycle:
typedef void (^MyVoidBlock)();
// MyTestClass
#property (nonatomic, copy) MyVoidBlock voidBlock;
self.voidBlock = ^{
[self doSomething]; // Warning!
};
Hope that makes sense :)
The code posted to github does cause a retain cycle.
Current github code:
#interface MyObject ()
#property (nonatomic, copy) dispatch_block_t codeToRunInFuture;
#end
#implementation MyObject
- (void) registerBlockForFuture:(dispatch_block_t)block {
self.codeToRunInFuture = block;
}
// Call in ViewController
self.myObject = [MyObject.alloc init];
[self.myObject registerBlockForFuture:^{
[self runThisInFuture];
}];
I can see where this would be difficult to catch since the Analyzer can not know what block might be and therefore can not tell if there is a self reference either strong or weak. It would have to examine all instances where registerBlockForFuture: is called and the block in each case.
The answer might be to submit a bugreport to Apple.

is it able to override NSObject init method to add every object into a single NSMutableArray?

I have a singleton object obj1, having a NSMutableArray member called Objects
and i added a category called NSObject (Register)
#implementation NSObject (Register)
-(id)init
{
[[obj1 defaultObject] addObjectToView:self];
return self;
}
#end
the addObjectToView method just simply add the object to the array
-(void)addObjectToView:(id)object
{
[object retain];
[Objects addObject:object];
}
(Object is a NSMutableArray)
the problem is, when i tried to test it, i did
NSWindow *window = [[NSWindow alloc] init];
and then i got 505 scary objects in the array,
did i do anything wrong?
BTW, it is possible to manage the relationship of all objects and send isolate objects dealloc message to implement a garbage collector in Objective-C ?
Don't do that!
This catches almost all objects created and prevents them from ever being deallocated. Actually even twice as you retain them manually and then add them to the mutable array which retains them as well.
Also you cannot override methods in categories. It sortof does work, but as soon as there is a second category that overrides the same method it's undefined which one will actually be used.
Implementing a garbage collector on top of that is not going to work either. Also you don't want a garbage collector. Apple used to provide one, but it is deprecated now and will be removed. Also you don't need it - use ARC.

NSArray and NSMutable Array. Type of property and type of ivar are not the same

I'm working through the big nerd ranch guide for Objective-C programming.
There is an example and challenge in chapter 21 that I've been stumped on. (I actually finished the challenge but I used previous code from an example) I'd like to actually understand what I did.
It has to do with declaring a property of type NSArray and then declaring the setter method to be of type NSMutableArray. Can anyone tell me what is going on here? What happens "behind the scenes" with this statement.
#property (nonatomic copy) NSArray *assets
and what is happening in these two files? Please explain at the lowest-level possible. Thanks!
BNREmployee.h
#interface BNREmployee: BNRPerson
{
NSMutableArray *_assets
}
#property (nonatomic copy) NSArray *assets
#end
BNREmployee.m
#implementation BNREmployee
- (void)setAssets:(NSArray *)a
{
_assets = [a mutableCopy]; //What did this actually do?
}
- (NSArray *)assets
{
return [_assets copy];
}
An NSMutableArray IS an NSArray (it is a subclass), so it just gets assigned normally. Nothing special happens behind the scenes.
An example I can give looking at your models would be assigning a BNREmployee object to a BNRPerson pointer which will work fine.
BNREmployee *employee = [BNREmployee new]; // or whatever initializer
BNRPerson *person = employee; // works fine, an employee IS a person
You can always assign an NSMutableArray to an NSArray pointer, but not the other way around.
Edit
"The property has type NSArray, which tells other classes, If you ask
for my assets, you are going to get something that is not mutable.
However, behind the scenes, the assets array is actually an instance
of NSMutableArray so that you can add and remove items in BNREmployee"
By exposing the public property as an immutable type you are letting any potential callers know that they can't modify the property without explicitly calling the mutator on the object. It also lets callers know once they get the collection, its contents will never be changed out from under them. This is the standard contract when exposing an immutable property. As pointed out in one of the comments below, there can be cases where a return type is immutable but the underlying object is actually mutable internally and can change, so good practice would be to make a copy when receiving the object if you are not already receiving an actual immutable copy, such as in the case of [NSView subviews].
Making the actual underlying variable a mutable type acts as a convenience to allow the owning class to modify it internally easily. Functionally, you could accomplish the same thing by making it a regular NSArray and constantly recreating it whenever you want to change its contents (such as array = [array arrayByAddingObject:object]). This will of course be slower than just modifying a mutable instance.

Objective C: Differentiating iVars and Accessors

#interface RandomObject : NSObject
{
NSString* someObject; // I know I don't have to explicitly declare. Just to clarify my point.
}
#property (nonatomic, strong) NSString *someObject;
#end
#implementation RandomObject
#synthesize someObject;
#end
Given the code above and Xcode 4.3 is used (hence, no auto-synthesizing), here is my question.
The property/synthesize will create accessors for someObject, namely getter and setter. So if I want to assign a value to someObject, I can do this.
self.someObject = #"Tomato"; // [self setSomeObject: #"Tomato"];
If my understanding is correct, self will send #"Tomato" to setSomeObject method. But what if you do this?
someObject = #"Tomato"; // or maybe _someObject = #"Tomato" if you are doing auto-synthesizing
Directly accessing an iVar object seems like a bad idea, but since someObject is a private variable, within the same class you have access to that, right?
I understand why you would need to use self.someOject if you want to manipulate someObject from another class. But why is it that you'd need to do the same even though you are still in the same class. Why is it that it's a bad idea to directly access iVar.
Generally speaking accessors have more pros than cons and I use them everywhere I can.
The main issue is that every place you reference the ivar directly is another potential place your code will need to change.
For example imagine you have referenced someObject in multiple places throughout your class. Then the requirements change and now you decide that when the value of someObject is assigned you need to so some other work. Due to the fact that you have accessed the ivar directly throughout the class you now have to either duplicate this new code everywhere you assign someObject or refactor. If you was using an accessor you just have one piece of code to change
- (void)setSomeObject:(id)anObject
{
if (anObject != someObject) {
someObject = anObject;
[self doSomeWork];
}
}
You can have the same issue with the getter - imagine you store an array of objects in someObjects - this works great but then later down the line you decide that you don't actually need to store someObjects as it can be dynamically computed from other values. If you have directly accessed the ivar everywhere then this becomes a big chore. If you stick to abstracting someObject behind a getter then all you now have to do is
- (NSArray *)someObjects
{
return [self calculateSomeObjects];
}
This is exactly the idea with non-ARC code, which puts the memory management of the ivar in one place (behind accessors) so that you do not have to litter your code with repetitive code.
The property does more than just assigning an object to the ivar.
If you don't use ARC, the property will auto-generate retain/release code to handle memory management. Just calling someObject = #"Tomato" creates a memory leak (if someObject is assigned)
If your property is atomic, the property will provide thread safety, while accessing the ivar would not be thread safe.
See https://stackoverflow.com/a/589348/1597531 for examples of auto-generated property code.

Lazy instantiation in Objective-C/ iPhone development

Quick question... Well I understand that all properties start out as nil in Objective-C and that sending a message to nil does nothing, therefore you must initialize using [[Class alloc] init]; before sending a message to a newly created property. However, what about if I'm not sending messages to this property or if I set the property using self.property = something? Do I need to alloc init in these cases as well? Also, do UI properties start out as nil as well, such as a UILabel property that you drag out from your storyboard? Do these need alloc init?
Thanks to all who answer
Stunner did a good job of explaining not needing to alloc init objects that have already been created.
But if it is an object that doesn't exist, where are you going to create it? A very common pattern, which I mention because you mentioned it in your post, is lazy instantiation.
So you want an NSMutableArray property. You could alloc init it in some method before you use it, but then you have to worry about "does that method get called before I need my array?" or "am I going to call it again accidentally and re-initialize it."
So a failsafe place to do it is in the property's getter. It gets called every time you access the property.
.h
#property (nonatomic, strong) NSMutableArray* myArray;
.m
#synthesize myArray = _myArray;
- (NSMutableArray*)myArray
{
if (!_myArray) {
_myArray = [[NSMutableArray alloc] initWithCapacity:2];
}
return _myArray;
}
Every time you access that property, it says, "Does myArray exist? If not, create it. If it does, just return what I have."
Plus an added benefit with this design pattern is you aren't creating resources until you need them, versus creating them all at once, say, when your view controller loads or your app launches, which, depending on the requirements, could take a couple seconds.
The reality is when you do self.myProperty = [[Class alloc] init], you're not initializing your property. Rather, you're initializing an object that you tell your property (which is in fact a pointer) to point to. So if you already have an object that's allocated and initialized, you don't have to alloc/init again and you can do self.myProperty = object;
UI Properties do no start as nil, this is because when you add elements in the interface builder, the view owns the elements that you add and these objects are initialized automatically for you. This means if you're creating IBOutlets and connecting them to some properties, you don't have to alloc/init.
I hope this was helpful.
I don't have experience with Storyboards but I know that when you create objects via a xib file all objects are properly instantiated when you tell a view controller to use a xib file. So you need not worry about alloc/initing those objects in code.
Regarding using self.property = <something>, it depends on what something is. If something is any sort of existing object you need not do the alloc init on that object as the self.property = ... syntax calls the property's setter method which will retain, copy, assign, etc. the new value to the property appropriately.
Now any sort of existing object can be an alloc/init'ed object, or an autoreleased object obtained from a convenience method (NSString's stringWithFormat: for example).
As Kaan Dedeoglu pointed out, the self.property = ... syntax points (and retains) the ivar to the object in memory, and it is up to you to initialize that object if it isn't already instantiated.
No you do not need to [[Class alloc]init the properties in your init method.
However, I would encourage you to explicitly set them to Nil in your init method for clarity.