Accessing obj as property vs method param (style preferences) - ios

When it comes to accessing objects from different methods in the same class, from what I understand, these are two ways to do it. Given that I DO want to hold a property pointer to this object, which is the better way to go about this? I've been thinking about this for a while, and wondered if there is a preference consensus.
#1:
NSArray *array = ... // Get array from somewhere
self.myArray = array;
[self doSomethingToMyArray];
This method takes no parameter and accesses the array via its own property via self
- (void)doSomethingToMyArray
{
// Do stuff with/to the array via self.myArray
[self.myArray ...];
}
Vs #2:
NSArray *array = ... // Get array from somewhere
self.myArray = array;
[self doSomething:array];
This method takes an array and accesses the array via its own method parameter
- (void)doSomething:(NSArray *)array
{
// Do stuff with/to the array via method parameter "array"
[array ...];
}

I think it's primarily going to depend on what doSomethingToMyArray does and who calls it.
Fairly obvious comments:
if you want to do that to more than one array, you need to take an argument;
if what you're doing is actually logically more to do with the array than with your class (e.g. you've implemented randomisation of the order of the array) then it'd be better as a category on NSArray rather than being anywhere in that class at all;
if there's any possibility of subclasses wanting to redefine the manner in which the array is obtained then you'll want to invoke the getter somewhere;
similar concerns apply if a subclass or an external actor should be able to intercede anywhere else in the process.
Beyond those concerns there are a bunch of us that just prefer this stuff to be functional anyway — noting that you're doing something to the array, not with the array, in which case you'd tend more towards self.myArray = [self processedFormOf:array] (or self.myArray = [array arrayByDoingSomething]; if the category tip makes sense).
So, ummm, I don't think there's a clear-cut answer.

That depends on what you want to do, just by reading it:
doSomething:array
I would assume the above method takes ANY array and performs an action, whereas:
doSomethingToMyArray
with this method you are describing the intention of doing something to your instance's array. Inside this method (given that you followed Apple good coding practices and you synthesized your property to _myArray) , you could either go with:
[self.myArray message]
or preferably
[_myArray message]

Your second option is sort of silly. If you're storing a pointer in an instance, then it's so that you can use it later (within that instance) without needing to pass it around whenever you call a method.
This is also dependent on whether you're using ARC or not (use ARC if this is a new project). In a non-ARC project, self.myArray = foo; will do a very different thing than myArray = foo; (the self. syntax calls a property, which in many cases will correctly retain the thing you've assigned). In an ARC project, they'll generally have the same behavior, and there's less room for error.
Personally, in my ARC projects, I do not use the self. syntax from within a class, since it's just extra typing for the same effect. This ties in nicely with the new usage of #property, where you're no longer required to write a #synthesize block, and Objective-C will automatically generate an ivar for you, with the name of your property prefixed by an underscore, i.e. _myPropertyName. That makes it very clear visually when you're accessing code from outside the class (crossing the encapsulation boundary), where things will look like foo.bar = baz; versus inside the class, where it's just _bar = baz;.

IMHO, clearly, a function call would incur an extra overhead.
you would have to allocate an object pointer (though minimal) over the stack (extra memory)
Have to pass it (extra processing)
Property is actually a small function call unless you have made customizations to the getter. I also assume that compiler may have its own optimizations put in place for such accessors so that you can access them with minimal overhead, though I do not have any source to cite this.

Related

Why isKindOfClass and isMemberOfClass works badly with NSString and NSMutableString?

I know Apple has cautioned against using it. But given their reasoning, the results are far from relevant and expected.
Here is my debug output - the results aren't different in code - below is just for brevity:
(lldb) po [#"Hello" isKindOfClass:[NSMutableString class]]
true => A mutable string?
(lldb) po [[#"Hello" mutableCopy] isKindOfClass:[NSMutableString class]]
0x00000001019f3201 => What's that?
(lldb) po [[#"Hello" mutableCopy] isMemberOfClass:[NSMutableString class]]
0x000000010214e400 => What's that?
(lldb) po [#"Hello" isMemberOfClass:[NSMutableString class]]
false => Once again?
Further to that, I removed all the string literal code and tested the following:
NSMutableString * m = [[NSMutableString alloc] initWithString:#"Hello"];
bool b = [m isKindOfClass:[NSMutableString class]];
NSLog(#"%d", b); --> 1 Expected.
b = [m isKindOfClass:[NSString class]];
NSLog(#"%d", b); --> 1 Expected.
b = [m isMemberOfClass:[NSString class]];
NSLog(#"%d", b); --> 0 Expected.
b = [m isMemberOfClass:[NSMutableString class]];
NSLog(#"%d", b); --> 0 Not Expected.
Is there an enlightenment?
UPDATE:
Apple's own take:
Be careful when using this method on objects represented by a class
cluster. Because of the nature of class clusters, the object you get
back may not always be the type you expected. If you call a method
that returns a class cluster, the exact type returned by the method is
the best indicator of what you can do with that object.
Why not simply say do not employ isKindOfClass and isMemberOfClass with cluster classes?
The explanation prevents use from the perspective such as:
You might end up modifying something that you are not supposed to.
instead of stating:
These methods do not work with class clusters.
(in the examples, I have shown above - I am clearly passing correct objects and still not getting expected results.)
UPDATE 2:
Filed with Apple Radar.
The methods don't "mislead" as you claim in the comments. Because NSString and NSMutableString are class clusters, they can return an instance of any concrete subclass that is-a NSString or NSMutableString, respectively.
As it happens, most concrete subclasses in the NSString cluster are also subclasses of NSMutableString. Instead of using the actual class to control mutability, they use a flag or something like that. All perfectly valid and complying with the design contract.
So, that's why [#"Hello" isKindOfClass:[NSMutableString class]] returns true. You ask "A mutable string?" No. That expression is not a valid test of mutability. As documented, there is no valid test of mutability. This is at the core of your misunderstanding. You must not attempt to interrogate the class of an object to determine if it's mutable. You must respect the static type of the pointer in the API.
Edit: This is documented in Concepts in Objective-C Programming: Object Mutability – Receiving Mutable Objects:
Use Return Type, Not Introspection
To determine whether it can change a received object, the receiver of
a message must rely on the formal type of the return value. If it
receives, for example, an array object typed as immutable, it should
not attempt to mutate it. It is not an acceptable programming practice
to determine if an object is mutable based on its class membership—for
example:
if ( [anArray isKindOfClass:[NSMutableArray class]] ) {
// add, remove objects from anArray
}
For reasons related to implementation, what isKindOfClass: returns in
this case may not be accurate. But for reasons other than this, you
should not make assumptions about whether an object is mutable based
on class membership. Your decision should be guided solely by what the
signature of the method vending the object says about its mutability.
If you are not sure whether an object is mutable or immutable, assume
it’s immutable.
A couple of examples might help clarify why this guideline is
important:
You read a property list from a file. When the Foundation framework processes the list, it notices that various subsets of the
property list are identical, so it creates a set of objects that it
shares among all those subsets. Afterward you look at the created
property list objects and decide to mutate one subset. Suddenly, and
without being aware of it, you’ve changed the tree in multiple places.
You ask NSView for its subviews (with the subviews method) and it returns an object that is declared to be an NSArray but which could be
an NSMutableArray internally. Then you pass that array to some other
code that, through introspection, determines it to be mutable and
changes it. By changing this array, the code is mutating internal data
structures of the NSView class.
So don’t make an assumption about object mutability based on what
introspection tells you about an object. Treat objects as mutable or
not based on what you are handed at the API boundaries (that is, based
on the return type). If you need to unambiguously mark an object as
mutable or immutable when you pass it to clients, pass that
information as a flag along with the object.
As others have mentioned, -isMemberOfClass: tests for being an instance of that exact class and not any subclass. For a class cluster, that will always return false, because the public class is abstract and will never have instances.
The other weird results are probably because you're using po (short for "print object") for non-object values. Use the p command for boolean expressions.
tl;dr Don't use introspection in your code to determine mutability or to vary behavior (outside of extremely limited situations). Do use static types and strongly defined data structures (including strongly defined plist structures).
The introspection functionality offered by the Objective-C runtime, of which the introspection methods on NSObject are implemented against, are neither misleading nor are they returning incorrect results.
They are revealing specific details of how the various objects are implemented. This may appear quite different from what is declared in the header files.
Or, to put it another way: compile time vs. run time may be very different.
That is both correct and OK. And confusing.
Objective-C implements a strong notion of duck typing. That is, if you have a reference to something declared as NSString*, it really doesn't matter what that reference really points to as long is it responds to the API contract declared for the class NSString.
The confusion comes from trying to treat Objective-C as a fully dynamic, introspection driven, language. It wasn't designed for that (well, it kinda was, but that notion was dropped by about 1990) and, over time, strong typing has become more and more the norm. I.e. let the compiler figure out if something is valid and don't try to second guess at runtime.

When to use alloc

Ive tried digging around in old posts, but they were kind of obsolete and years old, so I was concerned things might have changed due to ARC being introduced etc.
Mainly I was looking at some fairly new code that used alloc on an array, which was declared as a property in the header. I was thinking, I don't normally do this and everything is working smoothly. But then came to my mind UIButton and UILabel for example, which has to have alloc invoked, or they won't be added to the view when you want that. Are there any rough guidelines for when its actually needed. I would think any object needs this, but the array vs. button/label thing as I just described made me wonder what is the reasoning behind this.
Thanks in advance
This is 100% dependent on the actual objects being used from the framework. The really great news, though, is that Apple is extremely consistent. If you send a message that contains an "Alloc" in it anywhere, you are responsible for making sure that it has been released.
Here's a super document on it from Apple.
You use alloc always if you create the object on your own.
Which means that sending alloc is normally followed by an init method.
It might sometimes look like it's not always the case, as many classes have convenient constructors that return an already allocated and initialized object to you.
But there is still alloc and init called to create the object.
It's just done for you by the system.
But the difference between convenient constructors and manually creating objects isn't new to ARC, it has always been around.
Example for creating an NSArray on your own:
[[NSArray alloc]initWithObjects:#"Test", nil];
and as NSArray has an convenient constructor here the example for that:
[NSArray arrayWithObjects:#"Test", nil];
If you use ARC, there is no real difference.
Without ARC, the object returned by the convenient constructor would still be autoreleased, while the manually allocated object has to be released by you at a later point (or you have to add an autorelease after the init).
So the main difference is the owner ship:
In the manually created example the object belongs to you, so you are responsible to clean up after you don't need it anymore.
If something is declared in .xib then it is automatically allocated for you. Just use it. While If you are creating a view in code u must alloc it first. And if you have a property NSArray/NSMutableArray etc, u might be doing one of the following:
_array = [NSArray new];
_array = [[NSArray alloc] init];
_array = [NSArray arrayWithObjects: values count:2];
_array = # ["ABC", "xyz"];
etc,
so you are actually allocating it if you are using any of these methods.
I do not really understand, what
they won't be added to the view when you want that.
means, but here is the story:
Every object is allocated using +alloc. To be honest, it is +allocWithZone:, but this does not have any meaning at this place.
The very first message you have to send to the newly created instance object (remember: you sent +alloc to the class object) is an initialization message, something like init…. To put this together you will find code as:
… [[TheClass alloc] init…] …;
Because it is boring typing there are new allocators. They put this messages into one:
… [TheClass new…] …;
(This has some advantages for the class implementor, too, but this is transparent to you. Think of it as sending +alloc, -init….)
In earlier times it has been a good idea to send an autorelease message to it as the next step for some reasons:
… [[[TheClass alloc] init…] autorelease] …;
This has been put together to convenience allocators:
… [TheClass theClass…] …
This is what you find most of the time when reading old code. Using ARC you do not need convenience allocators anymore: There is no autorelease. So there is no reason for convenience allocators anymore. But we had MRR for years and there are still many convenience allocators. (Now called factory methods, but CA's are only a subset of these. A subset you do not have to care about. It's all gone with ARC.) Because there are that many CA's, one still uses them. (And there is a performance issue with them. In nowadays I only write new allocators, which has the advantages of a CA, but not the disadvantage of autorelease.)
To make a long story short: You simply do not see sometimes that +alloc is used.

function parameters not retained using Arc?

EDIT: This is for a static NSMutableDictionary, not a class member. I see a lot of answers thinking it's a class member, sorry about that. Thanks for the quick responses.
I had a working piece of code, but it was used 2x, so I wrote a convenience function:
- (void) initializeDictionary:(NSMutableDictionary*)mutableDict fromPathName:(NSString*)path
{
mutableDict = // get from file, init if not there.
}
Then I noticed nothing was saving. Stepping through the code, the function creates a dictionary, but the "passed in" value is still nil upon returning. This completely blows away my understanding of pointers (don't take this the wrong way, I'm very comfortable). But their purpose, I thought, was to let you "pass the address" so I could hydrate the thing it points to.
since mutableDict is the "value copy", ARC appears to be wiping it out. I'm asking here because
the other questions have the opposite question "Why is this being retained?" and
It doesn't seem right. Your very first tutorial in any pointer language is "so you can mess with the original value". Does Arc really do this? Is there a concept I'm not getting?
And of course, I may be overlooking something simple.
I seem to have solved it by doing the writeback trick I found elsewhere:
- (void) initializeDictionary:(NSMutableDictionary* __strong *)mutableDictionary fromPath:(NSString*)path;
and using the & to call and * deref to change the value. It just seems far less than elegant.
You pass a pointer of NSDictionary. If you change the pointer value of mutableDict (by allocation or assignment) this will NOT be reflected on the variable passed as this function's argument and since mutableDict is locally defined in the function it will be released by ARC automatically. (Do not forget that even for pointers the address is copied when passed to a function).
The reason that your second solution works is because you pass a pointer to a pointer (not sure if strong is needed there). The value of *mutableDict will be reflected outside since you update a value in the address pointed to by mutableDict. This value is the address of your allocated dictionary and since you change it via a pointer it will be reflected outside the function.
To do what you want you use multiple indirection
- (void) initializeDictionary:(NSMutableDictionary**)mutableDict fromPathName:(NSString*)path
{
mutableDict = // get from file, init if not there.
}
Notice the parameter is (NSMutableDictionary **), a pointer to a pointer to an NSMutableDictionary.
To call the method you need to create a pointer and pass it in like this:
NSMutableDictionary *mutableDictionary;
[self initializeDictionary: &mutableDictionary fromPathName:...];
And on return, the mutableDictionary variable will have been initialised by the method.
However, It's probably easier to just return the dictionary from the method rather than doing it this way.
In Objective-C if you define a variable in a method, the variable is visible only in that method.
If you need to save the variable to use it outside, you need to "return" it from your function. What you did wasn't a trick, is another way of returning a variable.
Try with:
- (void)initializeDictionaryFromPath:(NSString*)path {
NSMutableDictionary *mutableDict = // your initialization
return mutableDict;
}
Then you can define your dictionary with this code:
NSMutableDictionary *mutableDict = [self initializeDictionaryFromPath:path];

Initializing With Instance Methods versus Class Methods

Is there any performance difference between using class methods and instance methods to initialize an object?
In Apple's docs, I see the following, in the NSArray class (and I have seen this style in other classes too):
+ (id)arrayWithContentsOfFile:(NSString *)aPath
- (id)initWithContentsOfFile:(NSString *)aPath
The descriptions are very similar for each method.
Is there a performance difference?
Is one better than the other?
If they are both the same (in terms of performance), are there any times
that you would you use one method over the other?
Just curious. :P
The convenience constructor (+ version) will return an autoreleased value. Under ARC, this autorelease may be optimized away if the result is immediately assigned to a strong reference (using the objc_autoreleaseReturnValue/objc_retainAutoreleasedValue optimization).
The only time you need to be careful is with tight loops where using the + version may lead to lots of autoreleased objects getting created. If profiling reveals this to be a problem, consider using alloc+init instead inside such loops.
In general, you should go with whatever leads to cleaner code, which quite often means using the convenience (+) constructor.
Is there a performance difference?
Is one better than the other?
Not really, but it depends on exactly where you use them and what the surrounding context is.
If they are both the same (in terms of performance), are there any times
that you would you use one method over the other?
Personal preference mostly. The differences are in terms of memory management. The class method returns an autoreleased instance and you have no control over the zone it's allocated into. The instance method gives you control over those things.
Generally, and historically, on iOS you would avoid the autoreleased methods because you want to ensure that the memory used by the instance created is cleaned up quickly when you're done with it instead of being left until the pool is drained (because you usually don't know exactly when that will be). ARC reduces this concern though.
The difference between a class method and an instance method is that an
instance method requires an instance of the class on which it will
(generally) operate. The message to invoke an instance method must be
sent to an instance of a class.
For example
In Cocoa the NSString class has several class methods named
stringWithSomethingOrOther: that will create a new NSString object and
hand it back to you.
On the other hand, NSString also has many instance methods -
operations which really have no meaning without an actual instance to
work with. A commonly-used one might be the length method, which tells
you how many characters are in the specific NSString instance to which
the message is sent.
Suppose for another example-
#interface DeepsClass : NSObject
+ (void)myClassMethod;
- (void)myInstanceMethod;
#end
It can now be used like this : -
[DeepsClass myClassMethod];
DeepsClass *object = [[DeepsClass alloc] init];
[object myInstanceMethod];
Performance difference
Performance is almost the same in class methods & instance methods. Class methods are treated at runtime like any other methods (eg. instance methods), and while the Class may be loaded at runtime, the methods themselves are C functions, same as instance methods, and the POINTERS to those functions are cached, just like instance methods.
The only big difference is one give you autoreleased object and other don't.
The autoreleased object remains in the pool till the pool is released.
I love to use non-autoreleased object as whenever I'm finished with that object I just release it. In short you can dispose alloc-init object whenever you want, you just need a reference of this object.
//case 1:
for (int i = 0; i<1000; i++) {
NSArray *array = [[NSArray alloc] initWithContentsOfFile:#"path"];
//Do something with array
[array release];
}
//case 2:
for (int i = 0; i<1000; i++) {
#autoreleasepool {
NSArray *array = [NSArray arrayWithContentsOfFile:#"path"];
//Do something with array
}
}
//case 3:
#autoreleasepool {
for (int i = 0; i<1000; i++) {
NSArray *array = [NSArray arrayWithContentsOfFile:#"path"];
//Do something with array
}
}
Suppose your array takes 1KB, your first two cases will show peak of 1KB as objects are released immediately. In third cases your memory peak will go upto 1000KB and then comes back to zero after auto-released pool is released.
So it depends upon how you code.

Passing multiple parameters into function using array

I have to maintain a code of somebody. The code opens a thread. The thread worker function in iOS (and any other language I know of) accepts only one parameter. In order to overcome this, the code creates an array, adds all the parameters into an array and passes it into the thread. Here is the code.
NSArray* params = [[NSArray alloc] initWithObjects: mainView, actionFlag, nil];
[self performSelectorOnMainThread:#selector(updateWorker:) withObject:params waitUntilDone:NO];
And the function is called this way
-(void)updateWorker:(NSArray*)params
{
UIView* view = [params objectAtIndex:0];
bool actionFlag = ((NSNumber*)[params objectAtIndex:1]).boolValue;
/* do stuff with view and actionFlag */
}
I have a gut feeling that this is very wrong at so many levels but cannot built a valid argument for this case.
What are the drawbacks of passing number of arguments as an array?
Actually what you are doing is technically correct (but I do understand why it feels wrong).
If you want to feel better, what I would do in this case is instantiate (create) a "NSDictionary" object and then set the objects / values to useful keys and in your "updateWorker" method, fetch the objects via "objectForKey:".
Doing it this way will be easier for you (or somebody else) to maintain in the future, as you won't have to poke around to see what goes in array position 1, array position 2, etc.
Most of them are future updates,
Some cases (not so rare) may happen:
Addition of new parameters to the array
changing the order of elements in the array
removing elements in the array
problems when releasing and retaining elements in the array (not ARC)
One point to note here, is that all of these cases will be hard to debug, since you will be moving from one thread to the other

Resources