Bundle declarations into one statement or not? - objective-c

Given the following Objective-C example, is it simply a matter of style and ease of reading to keep separate statements or to bundle them into one? Are there any actual benefits of either? Is it a waste of memory to declare individual variables?
NSDictionary *theDict = [anObject methodToCreateDictionary];
NSArray *theValues = [theDict allValues];
NSString *theResult = [theArray componentsJoinedByString:#" "];
or
NSString *theResult = [[[anObject methodToCreateDictionary] theValues] componentsJoinedByString:#" "];

I take the following into consideration when I declare a separate variable:
If I might want to see its value in the debugger.
If I am accessing the variable more than once.
If the line is too long.
There is no practical difference between the two approaches, however.

Also, you haven't asked directly about this, but be aware, when you access objects using dot notation, for example:
myObject.myObjectProperty1.myObjectProperty1Property;
If you are going to access myObjectProperty1Property more than once, it can be advisable to assign it to a local named variable. If you don't, the look-up will be executed more than once.
Now I can't emphasise enough, for many if not most situations this time saving is so infinitesimal as to seriously call into question whether it is worth even spending the time doing extra typing for the assignation! So why am I raising this? Because having said that - stylistic "anality" apart (I just made up a new word) - if the section of code you are writing is running in a tight loop, it can be worth taking the extra care. An example would be when writing the code which populates the cells in a UICollectionView that contains a large number of cells. Additionally, if you are using Core Data and you are using the dot notation to refer to the properties of NSManagedObject properties, then there is far greater overhead with each and every look-up, in which case it is much more surely worth taking the time to assign any values referred to by "nested" dot notation calls to a local variable first.

Related

Objective-C Declaring Variables Within Loop -- Performance

I've been teaching myself Objective-C via some lectures from iTunes U.
I like the course, but the professor routinely writes code like this:
while (index < [self.textToAnalyze length]) {
NSRange range;
id value = [self.textToAnalyze attribute:attributeName atIndex:index effectiveRange:&range];
....
}
I have mostly worked in C and C++, and there are a couple of things about this code that seem glaringly wrong to me from a performance / style perspective.
The code declares two variables (of type NSRange and id) inside the loop. A naive compiler would reserve space for each of these types of variables at each iteration through the loop.
The code calls the length selector ([self.textToAnalyze length]) in the loop condition. As the programmer, I know that the length of the textToAnalyze property does not change while the loop is iterating. However, I'm not convinced that the compiler will know this. Won't this code call the length selector every single iteration of the loop?
I know that compilers can be very crafty, but I think it is bad code to declare variables within a loop and call functions within the loop conditions. It could affect the performance, and in my mind, it is certainly poor style.
However, I am new to Objective-C, so here is my question:
Is this bad code, or are these Objective-C idioms that are fine to use?
The answer is: it depends.
For variables in loops, moving them out of the loop might improve performance of the loop, but now you've changed the scope and effected performance in another way. Which is better is definitely going to be situation-based.
But, as far as I'm concerned, a variable with a scope any wider than necessary is bad practice. Variables with unnecessarily wide scope and lead to user error. The amount of performance improvement you might get here is not worth ANY amount of debugging that could've been avoided with a narrower variable scope.
As for calling methods in loop conditions, again, this depends.
I'm quite certain that the length method of NSString is quite optimized. The length of a string is not analyzed every time length is called, and especially not so for NSString (as opposed to NSMutableString. If we're talking about an immutable string, calling length is simply returning an NSInteger value stored within the class and performance will be fine.
If, however, we're talking about an immutable string, we need to call length every time if it's important that we're only within the length of the string.
It's a mutable string. Even if this loop doesn't modify the string, it can be modified else where by anyone that has a reference to it. If you're concerned about performance, make an immutable copy of the string and use that immutable copy in the loop.
[myString length]
According to this answer, for both mutable and immutable versions, there is a variable within the class that stores the string's length. For immutable strings, this is calculated when the string is created and never changed. For mutable strings, this variable is calculated and set each time the string changes. At the end of the day, when you call string, it's purely returning the value of an internally stored int value in the class and will not be any slower than storing this length in a separate variable before the loop and comparing against this.
I think it is theoretically possible for some loop conditions to be cached, but in practice that doesn't seem to happen — the length method will be called every time through the loop.
Does that make this bad code? Not necessarily. The overhead of a function call is not that huge. If this loop needs to be tight, then yes, caching the string's length is a great idea. But in many cases, it just doesn't make any measurable difference, so less code is better code.
As for declaring variables in a loop, that isn't problematic. There are two mainstream Objective-C compilers in existence, and neither has any trouble compiling that to efficient code. I doubt even POC has trouble with that. Muddling your variables' scope just to please a hypothetical awful compiler isn't good code — it's premature optimization. (Incidentally, the same holds true for C++ too.)

Minimising function names with lengthy parameters

We are using a web service to fetch data. As project progressed, number of params being passed between functions also increased. To make it more readable and easier to add/remove parameters in future thought of using a dictionary instead. So every function calls will have only one parameter , a dictionary with all required parameters in it.
So to set a parameter I need to do [aDictionary setObject:foo forkey:#"bar"] and to get a parameter, it would be [aDictionary objectForKey:#"bar"].
To access the variables easily I thought of using a Model class with all common parameters used as properties. So for one function call say 3 out of 10 properties would be used and rest will be not be set. So it would be like paramModel.foo = #"bar".
If I would do it like this, will I be wasting memory for unused properties which are not initialised. And is this right in doing so ?
Continuing Amin Negm-Awad's points: If you are finding yourself passing along a lot of parameters to many methods, you almost certainly have incorrectly defined your model classes. Rather than creating a generic dictionary, create a simple value object that holds the related properties.
As an example, consider NSURL. You would never do this:
[self handleScheme:scheme host:host path:path];
Instead you do this:
NSURL *URL = [[NSURL alloc] initWithScheme:scheme host:host path:path];
[self handleURL:URL];
This is the correct way to consolidate parameters, and to improve your design.
Also, if you're taking a large number of boolean parameters or other kinds of "options," first consider whether you have a method that is doing too many things. Perhaps it should just be broken up into multiple methods that each works a specific way. If you really do need to pass multiple boolean options, in ObjC, this is often done with bit fields rather than with many parameters. Look at [NSString rangeOfString:options:] for an example.
No, it is strange. (Of course this is a subjective opinion.)
A. "As project progressed, number of params being passed between functions also increased."
There is only a connection between size of a software and numbers of parameters to a method (in your example there is no function): if you do something wrong in your design.
Split your code into modules, into classes, define good relationships between them and so on.
Define classes that can hold connected data.
B. I cannot see, what becomes more readable using dictionaries:
[receiver doSomethingWithA:#"a"
B:#"b"
C:#"c"];
NSMutableDictionary *aDictionary = [NSMutableDictionary new];
[aDictionary setObject:#"a" forKey:#"A"];
[aDictionary setObject:#"b" forKey:#"B"];
[aDictionary setObject:#"c" forKey:#"C"];
[receiver doSomethingWithABC:aDictionary];
It is more code, it is more complex code (because it needs an additional instance object), arguments and its "parameter destination" are wrested apart.
Inside the method you have to read out the arguments from the dictionary. This is additional boiler plate code.

Objective-C String Differences

What's the difference between NSString *myString = #"Johnny Appleseed" versus NSString *myString = [NSString stringWithString: #"Johnny Appleseed"]?
Where's a good case to use either one?
The other answers here are correct. A case where you would use +stringWithString: is to obtain an immutable copy of a string which might be mutable.
In the first case, you are getting a pointer to a constant NSString. As long as your program runs, myString will be a valid pointer. In the second, you are creating an autoreleased NSString object with a constant string as a template. In that case, myString won't point to a real object anymore after the current run loop ends.
Edit: As many people have noted, the normal implementation of stringWithString: just returns a pointer to the constant string, so under normal circumstances, your two examples are exactly the same. There is a bit of a subtle difference in that Objective-C allows methods of a class to be replaced using categories and allows whole classes to be replaced with class_poseAs. In those cases, you might run into a non-default implementation of stringWithString:, which may have different semantics than you expect it to. Just because it happens to be that the default implementation does the same thing as a simple assignment doesn't mean that you should rely on subtle implementation-specific behaviour in your program - use the right case for the particular job you're trying to do.
Other than syntax and a very very minor difference in performance, nothing. The both produce the exact same pointer to the exact same object.
Use the first example. It's easier to read.
In practice, nothing. You wouldn't ever use the second form, really, unless you had some special reason to. And I can't think of any right now.
(See Carl's answer for the technical difference.)

Should I use an intermediate temp variable when appending to an NSString?

This works -- it does compile -- but I just wanted to check if it would be considered good practice or something to be avoided?
NSString *fileName = #"image";
fileName = [fileName stringByAppendingString:#".png"];
NSLog(#"TEST : %#", fileName);
OUTPUT: TEST : image.png
Might be better written with a temporary variable:
NSString *fileName = #"image";
NSString *tempName;
tempName = [fileName stringByAppendingString:#".png"];
NSLog(#"TEST : %#", tempName);
just curious.
Internally, compilers will normally break your code up into a representation called "Single Static Assignment" where a given variable is only ever assigned one value and all statements are as simple as possible (compound elements are separated out into different lines). Your second example follows this approach.
Programmers do sometimes write like this. It is considered the clearest way of writing code since you can write all statements as basic tuples: A = B operator C. But it is normally considered too verbose for code that is "obvious", so it is an uncommon style (outside of situations where you're trying to make very cryptic code comprehensible).
Generally speaking, programmers will not be confused by your first example and it is considered acceptable where you don't need the original fileName again. However, many Obj-C programmers, encourage the following style:
NSString *fileName = [#"image" stringByAppendingString:#".png"];
NSLog(#"TEST : %#", fileName);
or even (depending on horizontal space on the line):
NSLog(#"TEST : %#", [#"image" stringByAppendingString:#".png"]);
i.e. if you only use a variable once, don't name it (just use it in place).
On a stylistic note though, if you were following the Single Static Assigment approach, you shouldn't use tempName as your variable name since it doesn't explain the role of the variable -- you'd instead use something like fileNameWithExtension. In a broader sense, I normally avoid using "temp" as a prefix since it is too easy to start naming everything "temp" (all local variables are temporary so it has little meaning).
The first line is declaring an NSString literal. It has storage that lasts the lifetime of the process, so doesn't need to be released.
The call to stringByAppendingString returns an autoreleased NSString. That should not be released either, but will last until it gets to the next autorelease pool drain.
So assigning the result of the the stringByAppendingString call back to the fileName pointer is perfectly fine in this case. In general, however, you should check what your object lifetimes are, and handle them accordingly (e.g. if fileName had been declared as a string that you own the memory to you would need to release it, so using a temp going to be necessary).
The other thing to check is if you're doing anything with fileName after this snippet - e.g. holding on to it in a instance variable - in which case your will need to retain it.
The difference is merely whether you still need the reference to the literal string or not. From the memory management POV and the object creational POV it really shouldn't matter. One thing to keep in mind though is that the second example makes it slightly easier when debugging. My preferred version would look like this:
NSString *fileName = #"image";
NSString *tempName = [fileName stringByAppendingString:#".png"];
NSLog(#"TEST : %#", tempName);
But in the end this is just a matter of preference.
I think you're right this is really down to preferred style.
Personally I like your first example, the codes not complicated and the first version is concise and easier on the eyes. Theres too much of the 'language' hiding what it's doing in the second example.
As noted memory management doesn't seem to be an issue in the examples.

How can I remove the first element of an array in Objective C?

In Objective C, is there a one-liner or something small to remove (shorten by one) and return the first element of an array, regardless of its index?
I don't know of a method that returns the item removed, but you can do this using a combination of NSArray#objectAtIndex:0 and NSMutableArray#removeObjectAtIndex:0. I suppose you could introduce a new method category on NSMutableArray that implements a shift method.
That would be a poor thing to do.
Objective-C on the iPhone can actually use most of the performance perks of C.
If you look at some of my other posts, you'll see I'm ADAMANTLY against premature optimization, but when you are coding at the C level, there are just some things you don't do unnecessarilly.
Move memory
Duplicate structures
Allocate sparsely populated memory blocks
Inner loops
... (There are lots more, but my C-life is rusty and, as I said, I'm anti-optimization)
What you probably want is a well-implemented queue. Something that pre-allocates a large enough circular memory structure and then has two pointers that track the first and last bytes.
I'd be pretty surprised to hear that Objective-C didn't have a queue data structure.
Also, don't strive for the one-liners. All the stuff about terse code is overrated. If it makes more sense to call a method, so be it.
It's certainly too late to assist the original poster, but if you have a plain NSArray and not an NSMutableArray, this works well:
id myData = myArray.firstObject;
myArray = [myArray subarrayWithRange:NSMakeRange(1, myArray.count - 1)];
Cocoa array objects (NSArray/NSMutableArray) do not provide a one-line equivalent — you would have to read the object first, then remove it. The fact that these classes provide the methods -lastObject and -removeLastObject but not -firstObject and -removeFirstObject should be a reminder that removing from the front of an array is usually an inefficient operation, since the contents must be shifted (copied) one position forward. This is particular true for arrays in C, which are intrinsically tied with pointers.
If you're working with anything but primitive data types and/or very small arrays, you might want to consider that the behavior of "shifting off" the first element is indicative of a queue data structure. For details on how you might create a queue for objects, see this SO question. Personally, my opinion for that question is that a real queue class provides the cleanest programming idiom. You can even define your own method (perhaps as a category on NSMutableArray or another class) that does provide a one-liner to do what you want:
#interface NSMutableArray (QueueOneLiner)
- (id) removeAndReturnFirstObject; // Verbose, but clearer than "shift"
#end
#implementation NSMutableArray (QueueOneLiner)
- (id) removeAndReturnFirstObject {
id object = [[self objectAtIndex:0] retain];
[self removeObjectAtIndex:0];
return [object autorelease];
}
#end
However, by that point the solution will likely cause more overhead than it's worth, depending on the importance you place on simplicity versus performance of the code that uses it.
If you have an array obj *arr where obj is a class/typename and arr is the array, you can just say arr+1 to get the array without the first element.
Use this code,
[arrayName removeObjectAtIndex:0];
this may help you