Using sortUsingSelector on an NSMutableArray - objective-c

I have used sortUsingSelector to sort an NSMutableArray of custom objects.
Now I'm trying to sort an NSMutableArray containing NSMutableArrays of custom objects.
Can you use sortUsingSelector on an NSMutableArray, or does it only work for custom classes?

If you can use blocks, the most straightforward way using sortUsingComparator:. Otherwise, you'll need to use sortUsingFunction:.
In either case, you are going to need to write a custom block or function that takes two arrays as arguments and returns a sort order based on their contents (I'm not sure what logic you are using to determine if array A or array B is "before" or "after" the other).
You'd do something like:
static NSInteger MySorterFunc(id leftArray, id rightArray, void *context) {
... return ascending/descending/same based on leftArray vs. rightArray ...
}
Then:
[myArrayOfArrays sortUsingFunction: MySorterFunc context: NULL];

It sends the selector to the objects, so you'll need to use one of the other sorters. Probably sortUsingFunction:context:.

Of course you can also use sortUsingSelector:, it really doesn’t matter whats the object in your array as long as it responds to the selector you want to use. But NSMutableArray and NSArray don’t have any comparison methods themselves, so you’d have to extend them using a category to implement your compare method.
So you probably want to use the other sorting methods pointed out in the other answers here. It’s not impossible to use sortUsingSelector: but it is rather inconvenient and most people (including me) would argue that it’s bad style to write a category for that.

Related

Sorting an array breakdown

I've been reading through a few different programs that use the sortUsingSelector method to sort an array with string objects and I can't figure out how they do it.
Each program begins by defining the sort method as follows:
[myBook sort]; /**myBook is the name of the array in the addressBook class**/
-(void) sort
{
[book sortUsingSelector: #selector (compareNames:)];
}
/**compareNames is defined in the addressCard class**/
The sort method uses a selector method that seems to do all the work:
-(NSComparisonResult) compareNames: (AddressCard *) element
{
return [name compare: element.name];
}
Its important to note that there are two different classes: addressCard and addressBook.
I know the compare method returns NSOrderedAscending, NSOrderedSame, or NSOrderedDescending to the sortUsingSelector method. But, how do these methods go about sorting everything? I feel like I'm missing something huge. For instance, how does the compare method know which elements in the array to compare? I imagine that element[0] of the array is compared with element[1] and then a sort occurs then the next element is compared...Does the compare method have a default definition that I'm overlooking?
The compare: method (or any method you use as the parameter in sortUsingSelector:) just has one job: given exactly two objects (a pair), tell me how to order them. That is all it does.
It knows how to do this because it is defined by the class it is sent to. In this case, name is an NSString so we use NSString's definition of the compare: method - a definition that knows how to order strings (using rules about alphabetical order).
It is the sortUsingSelector: method that actually hands the compare: method pairs to, uh, compare. And how it chooses those pairs is its business. You are not told how it picks those pairs. Deciding what pairs to choose and in what order is a deep business; it is the subject of your Computer Science 101 class. But you are shielded deliberately from those details in this situation.

An Array of Blocks?

This seems like a very strange interaction to me but at the same time it not only works but throws no warnings or errors in the process. Just looking to get some better understanding of blocks in general and why something like this could be right or wrong.
Is there any reason why something like this shouldn't be done?
NSArray *array = [NSArray arrayWithObjects:^{NSLog(#"Block 1");}, ^{NSLog(#"Block 2");}, ^{NSLog(#"Block 3");}, nil];
for (id block in array) {
[block invoke];
}
Putting Blocks into NSArrays is fine; they're objects. In fact, they inherit from NSObject.
You do need to copy, them, however. Those Blocks are created on the stack and need to be moved to the heap in order to live past the end of the current method. If you're using ARC, this is easy:
NSArray *array = [NSArray arrayWithObjects:[^{NSLog(#"Block 1");} copy], ...
Under MRR, you need to balance that copy, so you have two unpleasant options: use temps, or enumerate the array right after creating it and send release to all its members.
Sending invoke, on the other hand, isn't completely kosher, because that's a private method. The only fully-API-compliant way to invoke a Block is with function-call syntax:
typedef GenericBlock dispatch_block_t;
for( GenericBlock block in array ){
block();
}
Sure, that's fine. Why wouldn't it be fine?
In languages like JavaScript this technique is commonplace when registering event handlers.
object.clickHandlers.push(function() { doStuff() });
object.clickHandlers.push(function() { doMoreStuff() });
I see no reason that similar techniques couldn't be used with ObjC blocks, as they are real objects.
The more interesting question to me though, is if this pattern is the best choice for whatever your goal is. Which you haven't really told us.
Blocks in Objective-C are "first-class citizen" objects. Whatever you can do to a regular object, be it passing as a parameter, storing in an array or a dictionary, and so on, you can do it to block objects as well.
For example, an array of block objects may be useful to encode a sequence of actions that is not known at compile time; a dictionary of block objects keyed by strings could be useful in implementing a scripting language, and so on.
The best way to call a block retrieved from a collection is casting it to its proper type, and using the regular block invocation syntax on it.

Is it possible to know an array (or arrays) which adding an object?

Follow is some code for example.
NSArray *test1 = [[NSArray alloc] initWithObjects:#"TEST", nil];
[someArray addObject:test1];
:
:
too many code lines.
:
:
At some place
NSArray *addingArray = [test1 whoisAddingOrContainingMe(?)];
I want to know a pointer of someArray as method of test1 instance.
Is there a method like this?
No, you can't "reverse lookup" the containers you are contained in.
From a design perspective this would be somewhat difficult, since conceptually there's no difference between having a reference to oneself in an "array", in any other container, or in any other object that's not considered to be a container. Thus, you have to record every single "retain" by passing it an additional "owner" parameter, and since retains and releases can be done in vastly different places you would also need to pass "owner" pointers around so that an eventual "release" can refer to the proper retain.
Or, to put it short: it would be a huge mess :-)
As suggested before, if you know what arrays can actually contain you -- and that should be much easier for your application -- you could check them. Or you could add a list to the objects to record where they have been added, probably via methods like "addTo:" and "removeFrom:".
I think you want NSArray's -containsObject: method.

Returning mutable vs. returning immutable (non-member-)objects

I hardly ever see the second one used and I wonder why?
Neither would it break support for situations where an NSArray is expected (as it's a subclass).
Nor would it break encapsulation by revealing mutable internals.
Under the precondition that it's never a mutable ivar that's returned, (which should be common sense anyway)
I can right now only think of advantages of using the second.
It actually is mutable. And muting is safe here, so why prevent it?
No need to call [[[foo fooBar] mutableCopy] autorelease], which needlessly allocates additional memory and needlessly wastes time.
Here are the method variations:
- (NSArray *)fooBar {
NSMutableArray *fooArray = [NSMutableArray array];
//populate fooArray
return fooArray;
}
- (NSMutableArray *)fooBar {
NSMutableArray *fooArray = [NSMutableArray array];
//populate fooArray
return fooArray;
}
I'm asking as my project has a bunch of methods with the same pattern.
And in most of the times the returned array will be modified afterwards (merged, edited, etc).
So I think it should be totally fine to return NSMutableArrays, yet nobody seems to be doing it.
NSMutableArray, NSMutableSet, NSMutableDictionary… it's basically the same deal.
For an explanation of using mutable versus immutable, check out Apple's documentation on Object Mutability.
In general, it is best to return an immutable version, unless it is specifically your intent that the object returned always be an immutable object available for any client to change. You should create your interfaces based on the intent of the interface, not off the current implementation. It is possible that requirements will change and you will need to change the implementation of fooBar such that it does return an instance variable. By returning mutable arrays you ensure that you encapsulate not only your instance variables, but your current implementation.
So, you may have a valid place to return a mutable array (I don't know), but you see most code passing immutable arrays because it fully encapsulates their variables and their implementations.
I suppose the first variation was preferred because polymorphism was preferred.
In either case, both methods return an instance of NSMutableArray, the only difference being that the first one hides that fact from the caller. In other words, the first variation is not safer than the second. It's essentially using polymorphism to tell the caller that any type of NSArray might be returned. If you need that kind of flexibility in your code, it definitely has it's advantages. (e.g., if one day, for whatever reason, you need to return a custom NSArray subclass, your code won't break at that level).
However, you seem to prefer communicating intent to the caller - i.e. that you actually return mutable arrays - which is also OK. To make everyone happy (if there is such thing anyways...), I suggest renaming the 2nd method to:
- (NSMutableArray *)mutableFooBar {
NSMutableArray *fooArray = [NSMutableArray array];
//populate fooArray
return fooArray;
}
As a side note, I think that the following is a slightly more efficient way to convert an existing immutable array into a mutable one:
NSMutableArray *mutableArray = [NSMutableArray arrayWithArray:fooArray];
(correct me if I'm wrong on that assumption).
I hope this answers your question...
Having a method return a mutable instance like that looks suspicious.
As the caller you have to question the original method signature and wonder if it really is safe to mutate the returned value. After all the class may inadvertently be returning a pointer to internal state.
If profiling reveals that this copy is indeed expensive, I usually change the method signature to make it obvious that the mutability is intended. Perhaps with something like:
- (void)populateFooBars:(NSMutableArray *)array;
That way it is clear that the mutability of the result is intentional.

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