Arrays of NSObjects in Objective-C - objective-c

I've created an object, and now I'm trying to create an array full of these objects. I've tried a few different things with no success.
How can I do this?

You can do it one of two ways, with NSArray or NSMutableArray.
id obj1, obj2, obj3;
// This creates a static array
NSArray *array = [NSArray arrayWithObjects: obj1, obj2, obj3, nil];
// This creates a dynamic array
NSMutableArray *mutarray = [NSMutableArray array];
[mutarray addObject:obj1];
[mutarray addObject:obj2];
[mutarray addObject:obj3];

NSMutableArray * arrayOfFoos = [NSMutableArray array];
for (int i = 0; i < 100; ++i) {
Foo * f = [[Foo alloc] init];
[arrayOfFoos addObject:f];
[f release];
}

You can use an NSArray, take a look at Apple's documentation.
If you wanna add them incrementally consider using a mutable collection like an NSMutableArray (here in the doc)

Related

Check that the contents of one NSArray are all in another array

I have one NSArray with names in string objects like this:#[#"john", #"smith", #"alex",
#"louis"], and I have another array that contains lots of names. How can I check that all the objects in the first array are in the second?
NSSet has the functionality that you are looking for.
If we disregard performance issues for a moment, then the following snippet will do what you need in a single line of code:
BOOL isSubset = [[NSSet setWithArray: array1] isSubsetOfSet: [NSSet setWithArray: mainArray]];
Use this code..
NSArray *temp1 = [NSArray arrayWithObjects:#"john",#"smith",#"alex",#"loui,#"Jac", nil];
NSArray *temp2 = [NSArray arrayWithObjects:#"john",#"smith",#"alex",#"loui,#"Rob", nil];
NSMutableSet *telephoneSet = [[NSMutableSet alloc] initWithArray:temp1] ;
NSMutableSet *telephoneSet2 = [[NSMutableSet alloc] initWithArray:temp2];
[telephoneSet intersectSet:telephoneSet2];
NSArray *outPut = [telephoneSet allObjects];
NSLog(#"%#",outPut);
output array contains:
"john","smith","alex","loui
as per your requirement.
Run a loop and use isEqualToStiring to verify whether array1 objects exists in mainArray.
int num_of_matches = 0;
for(NSString *name in mainArray)
{
if(array1 containsObject:name){
num_of_matches++;
}
}
if(num_of_matches == [array1 count]{
// All objects present
}else {
// Matched number is equal of number_of_matches
}
If you just need to check if all objects from array1 are in mainArray, you should just use NSSet
e.g.
BOOL isSubset = [[NSSet setWithArray:array1] isSubsetOfSet:[NSSet setWithArray:mainArray]]
if you need to check which objects are in mainArray, you should take a look at NSMutableSet
NSMutableSet *array1Set = [NSMutableSet setWithArray:array1];
[array1Set intersectSet:[NSSet setWithArray:mainArray]];
//Now array1Set contains only objects which are present in mainArray too
Use NSArray filteredArrayUsingPredicate: method. Its really fast to find out similar types of object in both arrays
NSPredicate *intersectPredicate = [NSPredicate predicateWithFormat:#"SELF IN %#", otherArray];
NSArray *intersectArray = [firstArray filteredArrayUsingPredicate:intersectPredicate];
From above code intersect array gives you same objects which are in other array.
Try this way;
NSArray *mainArray=#[#"A",#"B",#"C",#"D"];
NSArray *myArray=#[#"C",#"x"];
BOOL result=YES;
for(id object in myArray){
if (![mainArray containsObject:object]) {
result=NO;
break;
}
}
NSLog(#"%d",result); //1 means contains, 0 means not contains
You can use the concept of [NSArray containsObject:], where your objects will be from your array1 like you say "john","smith","alex","loui"
NSArray *array1 = [NSArray arrayWithObjects:#"a", #"u", #"b", #"v", #"c", #"f", nil];
NSMutableArray *mainArray = [NSMutableArray arrayWithObjects:#"a", #"u", #"I", #"G", #"O", #"W",#"Z",#"C",#"T", nil];
int j=0;
for(int i=0; i < mainArray.count; i++)
{
if (j < array1.count)
{
for( j=0; j <= i; j++)
{
if([[mainArray objectAtIndex:i] isEqualToString:[array1 objectAtIndex:j]] )
{
NSLog(#"%#",[mainArray objectAtIndex:i]);
}
}
}
}

Sort NSArray of custom objects based on sorting of another NSArray of strings

I have two NSArray objects that I would like to be sorted the same. One contains NSString objects, the other custom Attribute objects. Here is what my "key" NSArray looks like:
// The master order
NSArray *stringOrder = [NSArray arrayWithObjects:#"12", #"10", #"2", nil];
The NSArray with custom objects:
// The array of custom Attribute objects that I want sorted by the stringOrder array
NSMutableArray *items = [[NSMutableArray alloc] init];
Attribute *attribute = nil;
attribute = [[Attribute alloc] init];
attribute.assetID = #"10";
[items addObject:attribute];
attribute = [[Attribute alloc] init];
attribute.assetID = #"12";
[items addObject:attribute];
attribute = [[Attribute alloc] init];
attribute.assetID = #"2";
[items addObject:attribute];
So, what I would like to do is use the stringOrder array to determine the sorting of the items array of custom objects.
How can I do this?
Hereby, I compare directly the index of obj1.assetID in stringOrder with the index of obj2.assetID in stringOrder (using Objective-C literals for #() to transform NSString => NSNumber)
[items sortUsingComparator:^NSComparisonResult(Attribute *obj1, Attribute *obj2) {
return [#([stringOrder indexOfObject:obj1.assetID]) compare:#([stringOrder indexOfObject:obj2.assetID])]
}];
Or without ObjC literals :
[items sortUsingComparator:^NSComparisonResult(Attribute *obj1, Attribute *obj2) {
return [[NSNumber numberWithInt:[stringOrder indexOfObject:obj1.assetID]] compare:[NSNumber numberWithInt:[stringOrder indexOfObject:obj2.assetID]]]
}];
While cwehrungs answer will get the job done, the performance is not great on relatively small arrays.
Here is another method for performing the same kind of sort that is a bit quicker (though still far from perfect):
NSMutableArray *sorted = [NSMutableArray array];
// pre-populate with objects
for (int i = 0; i < stringOrder.count; i++)
{
[sorted addObject:[NSNull null]];
}
// place the items at the correct position
for (Attribute *a in items)
{
NSUInteger idx = [stringOrder indexOfObject:a.assetID];
if (idx != NSNotFound)
{
[sorted setObject:a atIndexedSubscript:idx];
}
}
// finally remove all the unecesarry placeholders if one array was smaller
[sorted removeObject:[NSNull null]];
Comparison
Here are the results form running the two methods on an iPhone 5:
sortUsingComparator:
100 - 0.012 s
1000 - 1.116 s
2000 - 4.405 s
3000 - 9.028 s
prepopulated array
100 - 0.003 s
1000 - 0.236 s
2000 - 0.917 s
3000 - 2.063 s
There are a couple approaches you could take.
You could store your Attribute objects in an NSDictionary, with the keys being the strings in your stringOrder array. Then, you could get a sorted array of the keys and use that to populate whatever view you're using to display them:
NSArray* sortedKeys = [dict keysSortedByValueUsingComparator:^(id obj1, id obj2) {
return [obj1 compareTo:obj2];
}
The other is that you make the sort order an intrinsic property of your Attribute object, so an array of Attributes can be sorted directly. I would only recommend taking this approach if the sort order is actually an intrinsic property of your Attributes object. If it isn't and you do this, you'll wind up storing presentation information where it doesn't belong.
Here's an example:
NSArray* sortedAttrs = [attributes sortedArrayUsingComparator:^(id obj1, id obj2) {
// Perform comparison of Attribute's, ahem, attributes
}
Here is the solution that I came up with that works extremely well. Anyone see performance issues with this?
for (Attribute *a in items) {
int index = [stringOrder indexOfObject:a.assetID];
a.sortOrder = index;
}
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"sortOrder" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray = [items sortedArrayUsingDescriptors:sortDescriptors];
Parallel Processing:
Results (quad core):
1. sortme:95 sortby:852345 sorted:95 time:0.052576
2. sortme:54248 sortby:852345 sorted:54243 time:0.264660
-(NSArray *)sortArray:(NSArray *)sortme sortBy:(NSArray *)sortBy{
CFAbsoluteTime time = CFAbsoluteTimeGetCurrent();
NSSet *sortmeSet = [NSSet setWithArray:sortme];
NSMutableDictionary *sortDictionary = [NSMutableDictionary dictionary];
dispatch_queue_t sortDictionaryThread = dispatch_queue_create("my.sortDictionaryThread", DISPATCH_QUEUE_CONCURRENT);
[sortBy enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([sortmeSet containsObject:obj]){
dispatch_barrier_async(sortDictionaryThread, ^{
sortDictionary[obj] = #(idx);
});
}
}];
__block NSArray *sortedArray = nil;
dispatch_barrier_sync(sortDictionaryThread, ^{
sortedArray = [sortDictionary keysSortedByValueUsingSelector:#selector(compare:)];
});
NSLog(#"sortme:%li sortby:%li sorted:%li time:%f",sortme.count,sortBy.count,sortedArray.count, CFAbsoluteTimeGetCurrent() - time);
return sortedArray;
}

How to put in array a different types of field in objective-c

I'm writing an app for iPhone in objective-c. I want to declare an array that will hold different type of fields , like: int, NSString, bool.
Can I do it?
You can put whatever items in an NSArray as long as they are objects. So you have to wrap items that are not objects (such as BOOL, int and CGPoint) in some kind of objects such as NSNumber or NSValue.
NSMutableArray *array = [[NSMutableArray] alloc] init];
[array addObject:myString];
[array addObject:[NSNumber numberWithInt:1]];
[array addObject:[NSNumber numberWithFloat:1.0]];
[array addObject:[NSValue valueWithPoint:myPoint]]; // myPoint is a CGPoint
[array addObject:[NSValue valueWithRect:myRect]]; // myRect is a CGRect
Yes, you can
NSMutableArray *array = [NSMutableArray array];
NSString *string = #"str";
[array addObject:string]; //string
NSNumber *num = [NSNumber numberWithInt:1];
[array addObject:num]; //int
NSNumber *boolNum = [NSNumber numberWithBool:YES];
[array addObject:boolNum]; //bool
Use NSMutableArray.
NSMutableArray *array = [[NSMutableArray alloc]init];
Now use addObject: method to add objects. for adding int, bool value create NSNumber object.
It is possible. Just create the array and add the objects you want added.

NSArray filled with bool

I am trying to create an NSArray of bool values. How many I do this please?
NSArray *array = [[NSArray alloc] init];
array[0] = YES;
this does not work for me.
Thanks
NSArrays are not c-arrays. You cant access the values of an NSArray with array[foo];
But you can use c type arrays inside objective-C without problems.
The Objective-C approach would be:
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:[NSNumber numberWithBool:YES]];
//or
[array addObject:#(NO)];
...
BOOL b = [[array objectAtIndex:0] boolValue];
....
[array release];
EDIT: New versions of clang, the now standard compiler for objective-c, understand Object subscripting. When you use a new version of clang you will be able to use array[0] = #YES
Seems like you've confused c array with objc NSArray. NSArray is more like a list in Java, into which you can add objects, but not values like NSInteger, BOOL, double etc. If you wish to store such values in an NSArray, you first need to create a mutable array:
NSMutableArray* array = [[NSMutableArray alloc] init];
And then add proper object to it (in this case we'll use NSNumber to store your BOOL value):
[array addObject:[NSNumber numberWithBool:yourBoolValue]];
And that's pretty much it! If you wish to access the bool value, just call:
BOOL yourBoolValue = [[array objectAtIndex:0] boolValue];
Cheers,
Pawel
Use [NSNumber numberWithBool: YES] to get an object you can put in the collection.

Can a function return an object? Objective-C and NSMutableArray

I have an NSMutableArray. It's members eventually become members of an array instance in a class. I want to put the instantiantion of NSMutable into a function and to return an array object. If I can do this, I can make some of my code easier to read. Is this possible?
Here is what I am trying to figure out.
//Definition:
function Objects (float a, float b) {
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:[NSNumber numberWithFloat:a]];
[array addObject:[NSNumber numberWithFloat:b]];
//[release array]; ????????
return array;
}
//Declaration:
Math *operator = [[Math alloc] init];
[operator findSum:Objects(20.0,30.0)];
My code compiles if I instantiate NSMutableArray right before I send the message to the receiver. I know I can have an array argument along with the method. What I have problem seeing is how to use a function and to replace the argument with a function call. Any help is appreciated. I am interested in the concept not in suggestions to replace the findSum method.
Use autorelease to return objects you create in methods/functions.
NSMutableArray* Objects(float a, float b) {
NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease];
// or: [NSMutableArray array];
[array addObject:[NSNumber numberWithFloat:a]];
[array addObject:[NSNumber numberWithFloat:b]];
return array;
}
Or simply:
NSMutableArray* Objects(float a, float b) {
return [NSMutableArray arrayWithObjects:
[NSNumber numberWithFloat:a],
[NSNumber numberWithFloat:b],
nil];
}