Apply a block to all objects of an NSArray - cocoa

Is there a way to apply a block to all the objects of an array?
Let's say I have an amazing block:
void (^myAmazingBlock)(NSNumber *) = ^(NSNumber *aFooNumber) {
NSLog(#"Log message from an Amazing Block: %#", aFooNumber);
};
To apply my block to all the objects of my array, this works:
for (NSNumber *aNumber in myArray) {
myAmazingBlock(aNumber);
}
Is it possible to get rid of the fast enumeration loop, and have something similar in the spirit to:
[myArray valueForKeyPath:#"#distinctUnionOfObjects.^myAmazingBlock"]; // This code doesn't work. It's just to show the style of what I'm trying to write.
I don't have any specific use in mind ; I was just being curious of the other possible ways to write this.
Edit:
It's possible to use enumerateObjectsUsingBlock: (Thank you paulbailey).
You then have to declare your block like this:
void (^myAmazingBlock2)(id, NSUInteger, BOOL *) = ^(id aFooNumber, NSUInteger idx, BOOL *stop) {
NSLog(#"Amazing BLOCK 2 %#", aFooNumber);
};
[myArray enumerateObjectsUsingBlock:myAmazingBlock2];
Unfortunately, the fast enumeration loop is still the most readable solution.

You could use enumerateObjectsUsingBlock: perhaps? Obviously you'd have to adapt the parameters of your block to match those specified.
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/NSArray.html

Related

Why can I not identify simple string key values in a database (core data)

I am a newbie so I apologise if I am missing something obvious.
I am trying to write an app in Xcode 4 to produce stats for my local sports team.
This is the relevant detail of the problem area of my programme:
NSError *error;
NSArray *games = [context executeFetchRequest:fetchRequest error:&error];
if (games == nil) {
NSLog(#"There was an error!");
}
int noOfBatOuts = games.count;
int noOfNotOuts=0;
for (NSManagedObject *oneMatch in games) {
if ([oneMatch valueForKey:#"batOut"]==#"NO") {
noOfBatOuts = noOfBatOuts - 1;
noOfNotOuts = noOfNotOuts + 1;
NSLog(#"Not Out!");
}
NSLog(#"How out %#",[oneMatch valueForKey:#"batOut"]);
}
notOuts.text=[NSString stringWithFormat:#"%d",(noOfNotOuts)];
NSLog(#"No of Not Outs is %#",notOuts.text);
When I run with data that has a not out string - NO, - the NSLog(#"Not Out!") is never called and the final NSLog(#"No of Not Outs...) reports zero. However I know that the data is there and it is identified in the middle NSLog(#"How Out....).
I am starting to tear my hair out in frustration and not having the knowledge yet to know the answer. Can anybody help please?
I would assume that batOut is a Boolean rather than string type, in which case you should be checking for truth rather than string equality.
If batOut really is a string, then you still can't compare strings this way. You need to use isEqual: or isEqualToString:. For example:
if ([[oneMatch valueForKey:#"batOut"] isEqual:#"NO"]) {
Normally you'd use isEqualToString: for string comparisons, but -valueForKey: is an id so isEqual: is safer.
The == operator checks that two pointers have the same value. Two strings can have the same contents but not be stored in the same memory.
You can't compare strings with ==. Use NSString's isEqualToString:

Fast enumeration on an NSIndexSet

Can you fast enumerate a NSIndexSet? if not, what's the best way to enumerate the items in the set?
In OS X 10.6+ and iOS SDK 4.0+, you can use the -enumerateIndexesUsingBlock: message:
NSIndexSet *idxSet = ...
[idxSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
//... do something with idx
// *stop = YES; to stop iteration early
}];
A while loop should do the trick. It increments the index after you use the previous index.
/*int (as commented, unreliable across different platforms)*/
NSUInteger currentIndex = [someIndexSet firstIndex];
while (currentIndex != NSNotFound)
{
//use the currentIndex
//increment
currentIndex = [someIndexSet indexGreaterThanIndex: currentIndex];
}
Fast enumeration must yield objects; since an NSIndexSet contains scalar numbers (NSUIntegers), not objects, no, you cannot fast-enumerate an index set.
Hypothetically, it could box them up into NSNumbers, but then it wouldn't be very fast.
Short answer: no. NSIndexSet does not conform to the <NSFastEnumeration> protocol.
Supposing you have an NSTableView instance (let's call it *tableView), you can delete multiple selected rows from the datasource (uhm.. *myMutableArrayDataSource), using:
[myMutableArrayDataSource removeObjectsAtIndexes:[tableView selectedRowIndexes]];
[tableView selectedRowIndexes] returns an NSIndexSet.
No need to start enumerating over the indexes in the NSIndexSet yourself.
These answers are no longer true for IndexSet in Swift 5. You can perfectly get something like:
let selectedRows:IndexSet = table.selectedRowIndexes
and then enumerate the indices like this:
for index in selectedRows {
// your code here.
}

Attempt to insert nil

Seems like it should be easy to add a boolean to an NSMutableArray.
Assume toDoArray is intialized as an NSMutableArray. The following:
BOOL checkBoxState = NO;
[toDoArray addObject:checkBoxState];
Generates the error "attempt to insert nil."
What's the correct way to add a negative boolean to a mutable array?
As others have said, NSMutableArray can only contain Objective-C objects. They do not have to be subclasses of NSObject, but that is the most typical.
However, long before you ever see the attempt to insert nil. runtime error, you should have seen a compiler warning:
warning: passing argument 1 of 'addObject:' makes pointer from integer without a cast
It is [in a vague and roundabout way] telling you exactly what the problem is; you are trying to stick something into an array that is not a pointer [to an object].
Pay attention to warnings and fix them. Most of the time, the presence of a warning will indicate a runtime error or crash.
NSMutable arrays require an id, a weird part of Objective C. An id is any object, but not a primitive (For example, ints are primitives, while NSArrays are objects, and in extension, ids).
This question might help.
You need using NSNumber to wrap any primitive types (BOOL, int, NSInterger, etc.) before placing it inside collection object (NSArray, NSDictionary, etc.).
Add BOOL to array:
BOOL checkBoxState = NO;
NSNumber* n = [NSNumber numberWithBool:checkBoxState];
[toDoArray addObject:n];
Get BOOL from array:
NSNumber* n = [toDoArray objectAtIndex:0];
BOOL checkBoxState = [n boolValue];

How do I select a random key from an NSDictionary?

When I was using an NSArray, it was easy:
NSArray *array = ...
lastIndex = INT_MAX;
...
int randomIndex;
do {
randomIndex = RANDOM_INT(0, [array count] - 1);
} while (randomIndex == lastIndex);
NSLog(#"%#", [array objectAtIndex:randomIndex]);
lastIndex = randomIndex;
I need to keep track of the lastIndex because I want the feeling of randomness. That is, I don't want to get the same element twice in a row. So it shouldn't be "true" randomness.
From what I can tell, NSDictionary doesn't have something like -objectAtIndex:. So how do I accomplish this?
You can get an array of keys with allKeys (undefined order) or keysSortedByValueUsingSelector (if you want sorting by value). One thing to keep in mind (regarding lastIndex) is that even with sorting, the same index may come to refer to a different key-value pair as the dictionary grows.
Either of these (but especially keysSortedByValueUsingSelector) will come with a performance penalty.
EDIT: Since the dictionary isn't mutable, you should just be able to call allKeys once, and then just pick random keys from that.
You could use the code below:
- (YourObjectType *)getRandomObjectFromDictionary:(NSDictionary *)dictionary
{
NSArray *keys = dictionary.allKeys;
return dictionary[keys[arc4random_uniform((int)keys.count)]];
}
To make it more efficient, you can cache keys in an instance variable. Hope this helps.

How can I access specific subsets of a large NSDictionary in Cocoa?

I have a single NSDictionary object which contains a large number of custom objects. The objects will either be of class B or of class C, both of which inherit from class A. If the objects are of type B, they will have an internal flag (kindOfCIsh) which will be used for future grouping.
How can I, at different times in my program, get an NSDictionary (or NSArray) that contains different groupings of those objects? In one case, I will want all of B, but another time I will want all of the C objects, plus the B objects that satisfy (kindOfCIsh == true).
Is there a simple way to get access to these subsets? Perhaps using filter predicates? I can, of course, loop through the entire dictionary and build the required subset manually, but I have a feeling that there is a better way.
Any help is appreciated.
[[myDictionary allValues] filteredArrayUsingPredicate: pred];
You can use categories
the code is something like this
#interface NSDictionary (dictionaryForClass)
-(NSMutableDictionary *) dictionaryWithObjectsKindOfClass:(Class)myClass;
#end
#implementation NSDictionary (dictionaryForClass)
-(NSMutableDictionary *) dictionaryWithObjectsKindOfClass:(Class)myClass;
{
NSMutableDictionary *ret = [[[NSMutableDictionary alloc] init] autorelease];
for (id object in self) {
if ([object isKindOfClass:myClass]) {
[ret addObject:object];
}
}
return ret;
}
#end

Resources