when to use the various sort methods of NSArray? - iphone

The doco explains what the NSArray sort methods are, but is anyone able to give a bullet point say on when/why you'd use a particular method? i.e. under what circumstances in you code would you use method XXX over method YYY. For:
sortedArrayUsingComparator
sortedArrayUsingDescriptors
sortedArrayUsingFunction:context
sortedArrayUsingSelector

See Collection Programming Topics: Sorting Arrays for more general information. If you're looking at the class reference documentation, be sure to check out the "Companion guides" that are listed for more practical, real-world advice on how the classes work.
Basically, sortedArrayUsingSelector: and sortedArrayUsingFunction:context: have been around since 10.0/iOS 2.0. They're not as flexible as the other methods which came later.
If you have an array of relatively simple objects, like NSNumbers or NSStrings, you could use [numbers sortedArrayUsingSelector:#selector(compare:)] to easily sort the objects.
If, on the other hand, you have a more complex model object that has multiple properties, such as age, name, date, NSSortDescriptors work well. Those were added in OS X 10.3/iOS 2.0. The allow you to do something like first sort by age, then by name, and then by date.

Related

Simplest way to encapsulate multiple method arguments?

+ (Planet *)createPlanetInContext:(NSManagedObjectContext *)context
withName:(NSString *)name
type:(NSString *)type
group:(NSString *)group
andDiameter:(NSNumber *)diameter {
If I wanted to encapsulate the arguments "name", "type", "group" and "diameter" into a single entity for passing to the above method what is the best type to use for encapsulation? The above method is just a quick example which you could argue is just fine as presented, but what if there were many more arguments that needed to be passed. I would need to package the data before calling the method so the solution needs to be something quick and simple to setup.
+ (Planet *)createPlanetWithData:(Data *)data inContext:(NSManagedObjectContext *)context {
Or is it more inline with objective-c practices (more readable) to individually list all the arguments?
I'd say generally you would want to individually list your arguments, for clarity. The sample method you've posted above isn't terribly long, in the context of Objective-C.
It's really to do with readability and documentation. When you list all the arguments it's clear to developers coming to your project what's being passed in where, and what kinds of objects are floating around. Automatic documentation generation (eg, Doxygen) also works off lists of arguments particularly well.
But there is a point at which, as you say, it becomes a little unwieldy. Twenty parameters to pass in and your method calls are going to be very, very long! So there are other options available - the easiest one is probably to use a NSDictionary or similar, which is used already in iOS to ferry certain bits of data around (particularly with notifications, where you have the userInfo dictionary).
Reading code is harder than writing code, so optimize for readability. Shortness of selectors should not be a factor; clarity should be.
Ask yourself which version is more readable, and stick to that one. I think it's relatively obvious that the version with the direct arguments is more readable.
Objective-C has wonderful syntax for methods with multiple arguments, so use this to your advantage. In a language with c-like syntax, I'd also hesitate to use many arguments.
You could populate a dictionary with one key/value pair per property on your NSManagedObject.
If you want to be super flexible, you could go with #Novarg's comment and pass a dictionary as your argument. That way, you can add parameters to it without affecting your method signature.
I have a particular preference for creating a custom args object to pass into my methods. This not only has the flexibility of a dictionary, but also may have some built-in utilities or additional logic. Also, unlike a dictionary, you don't need to hardcode key names and/or constants, and is MUCH easier to refactor if you, say, need to change a name of a property using Xcode's refactoring capabilities:
+ (Planet *)createPlanet:(PlanetArgs *)args
{
//args.context
//args.name
//args.type
//args.group
//args.diameter
//Args can even have some built-in logic
//planet.color = [args generateRandomColor]; <<-Just a rough idea
}

NSOrderedSet for iPhone?

For some odd reason NSOrderedSet does not appear to be implemented in iOS. Is there another object that gives similar functionality -- basically the ability to insert/remove objects randomly and access the first/last in sort order?
It seems to me that something like this would be needed in order to implement basic FIFO queues and the like.
Edit: I ended up doing an RYO solution.
One option is this open source data structures library:
http://dysart.cs.byu.edu/CHDataStructures/index.html
In that library is a CHOrderedSet
http://dysart.cs.byu.edu/CHDataStructures/interface_c_h_ordered_set.html
It's only dependency is NSMutableSet so it should work across all your iOS versions.
EDIT:
As Bourne pointed out above, it's also in iOS5 (reference):
The new NSOrderedSet collection class offers the semantics of sets,
whereby each element occurs at most once in the collection, but where
elements are in a specific order.
CHOrderedSet is a good option if you don't have a hard dependency on iOS5.
NSOrderedSet and NSMutableOrderedSet are not available in iOS 5. Here's the reference for anyone curious:
http://developer.apple.com/library/ios/#documentation/Foundation/Reference/NSMutableOrderedSet_Class/Reference/Reference.html#//apple_ref/occ/cl/NSMutableOrderedSet

Are there any reasons why I should prefer an NSArray instead of NSMutableArray?

I feel that when I use NSArray, I might constraint myself some time in future. Are there any good reasons to prefer this "primitive" one instead of the "complex" one, which is mutable?
Using a non-mutable structure in your code is not much of a constraint - if it turns out that you need to modify it later on you can change to use a mutable one. It can be more of a constraint if you have it in an external interface mind you. The main advantages of non-mutable is that you gain thread safety and it is more easy to conceptualize the code - there is less to concern you if mutability is taken out of the equation. This is why we have const constraints and so on - if you don't have to modify the data it is better to say so up front.
One reason is the YAGNI principle. If you don't need a mutable array, don't use it. So your code will be easier to understand, test and maintain.
Remember that code is not only processed by a compiler but also read by coders or testers. Using NSMutableArray instead of NSArray has a meaning for them. It may be counterproductive to give them false information about your intentions.
In addition to the answers from Mssrs INFORMATION and mouviciel NSArray is faster than NSMutableArray. This is true for all the stati/mutable collections.

Dictionaries in Project Structure

I am wrapping up an application where I am using a lot of Dictionary classes to store Function and Action delegates. I am now refactoring my project a bit and cleaning code. My question is where do or would you put your Dictionary classes in your project structure? Right now, they are located within the calling class source files but I was wondering if I should create a separate source file to store all my Dictionaries. I hope this is enough information. Please forgive me if it is not. Thanks.
I would organize the dictionaries in the same way as the rest of the code; group related functionality together, and separate unrelated functionality.
In addition, I'd look at how the delegation dictionaries are used. If your usage pattern is always to retrieve a delegate and immediately invoke it, then I'd wrap that behavior into a class with a "do-the-right-thing" method. Then each such class can be named by the domain concept it represents.
For example, if you had a dictionary which mapped US state abbreviations to a sales tax calculation, then you could wrap all of that into a class with a "compute sales tax" method taking a state code and subtotal as arguments. The fact that it's using a dictionary to look up the right computation scheme then becomes a hidden implementation detail.
Normally, the Dictionary class would be a thing unto itself (a library) and your various users would create instances of it.
If need be, they might specialize / sub-class it, but this should be rare.
Maybe the question you really should be asking yourself "why do I have multiple Dictionary classes"?

iPhone: Data structure choice

I need to keep track of a bunch of objects that can be identified by two keys (Latitude and longitude actually, but there are some other properties). I need to do things like search for a particular object by those two keys, updating it if it is there and inserting if not. I was thinking. I was looking at NSDictionary and NSSet but thought I would hear what the masses have to say.
I guess the simpler way is to use NSDictionary. You will be able to get your data by just doing [dic objectForKey:key].
Also, a good practice is to create some defines for the keys, so that it's easier to change a key name, and also avoids typo:
#define kObjectLatitude #"Latitude"
#define kObjectLongitude #"Longitude"
[object setObject:lat forKey:kObjectLatitude];
[object setObject:lon forKey:kObjectLongitude];
Don't forget to write the defines in a smart place. If you use it only in one class, just write them at the top of the declaration. If, however, you need them through different part of your code, you might consider moving it to the header file of the main class, or a specific header file for defines :)
NS(Mutable)Set will not be useful for you in this case. NSSets are mathematical sets, and you cannot access a specific data with a specific key (aka, you can't ask a set: "Hey, give me the longitude, where-ever you stored it!")
This is not a direct answer, but a word of warning. Latitude and longitude are CLLocationDegrees, which is a double precision floating point value. Testing for equality on floats is a risky proposition since floating point math is inexact. You can easily have an equality test fail on two floats that should theoretically be equal. I don't know the requirements of your application, but you may want to test for proximity rather than equality.
Use NSDictionary. That's what it meant for.