What are the basic differences between these ways creating and handling arrays? - iphone

I am unsure which way to declare my arrays with fixed size of 10 objects of type MyClass and what are the implications of these different alternatives for efficiency, ease of coding or anything else.
...keeping in mind the new xCode4.4 features, esp:
For the NSArray and NSDictionary classes, support is provided for
Objective-C literals.
Subscripting using '[ ]' syntax is supported for Objective-C
container objects.
...and of course using ARC
In particular I need to write contructor methods that return these arrays as a result.
Alternative1
MyClass* objectOfMyClass;
MyClass* array1[10];
array1[5] = objectOfMyClass;
Declaration of method:
- (MyClass*[]) createArray { <--- is this declaration correct like this ?
ps. AFAIK these arrays are put on the stack memory - but I am not sure!
Alternative2
MyClass* objectOfMyClass;
NSMutableArray *array2 = [[NSMutableArray alloc] init];
for (int i = 0; i<10; i++)
[array2 addObject:objectOfMyClass]; //objects get added in some way...
//can't directly access nTh object in this case, need to add from 0 to 9
//conversion to non mutable array, since size will not change anymore
NSArray *array3 = [NSArray arrayWithArray:array2];
Declaration of method:
- (NSArray*) createArray {
ps. AFAIK these arrays are put in main memory - not stack - but I am not sure!
Alternative3
NSArray *array4 = [[NSArray alloc] init];
array4 = ...how to prepare the array so it can hold 10 objects without using NSMutableArray ?
otherwise I do not see a difference to alternative 2...
for (int i = 0; i<10; i++)
array4[i] = objectOfMyClass];
Declaration of method:
- (NSArray*) createArray {
Many thanks for bringing light into this!

There is a great article about literals here. You cannot do Alternative 1. The best way to do this is:
NSMutableArray *holdsMyClass = [NSMutableArray arrayWithCapacity:10]; // sized so array does not need to realloc as you add stuff to it
You cannot arbitrarily increase the size of the array by indexing past the size - if you have an object at index 5, you can replace it though:
holdsMyClass[5] = obj;
For example, if you try to compile this, it fails:
- (NSArray*[]) createArray
{
NSArray *foo[10];
foo[2] = [NSArray array];
return foo;
}
generates this error: "array initializer must be an initializer list"

Related

Put all object properties into an NSDictionary or NSArray

Is there a way to automatically return an NSDictionary of all the (public) properties in a class? You can assume all properties are property lists and that I don't want to just hand over a pointer to the class itself. Any existing magic that can pull this off?
I know I can lazy instantiate an NSDictionary and manually fill it with properties in the getter.
It's easy to get an array of declared properties using the class_copyPropertyList and property_getName functions in the Objective-C runtime. Here's one such implementation:
- (NSArray *)properties
{
NSMutableArray *propList = [NSMutableArray array];
unsigned int numProps = 0;
unsigned int i = 0;
objc_property_t *props = class_copyPropertyList([TestClass class], &numProps);
for (i = 0; i < numProps; i++) {
NSString *prop = [NSString stringWithUTF8String:property_getName(props[i])];
[propList addObject:prop];
}
return [[propList copy] autorelease];
}
You could add this as a method in a category on NSObject. Here's a full code listing that can be compiled that demonstrates this.
I'm not sure how'd you do it with an NSDictionary, only because I'm not sure what you expect the key-value pairs to be.

error in array cleaning method

I am attempting to use this array cleaning method, and there seems to be an error. I can't spot it, I know the array goes in with 3116 items, comes out with 3116 (and I know for a fact there are three duplicates.
Please advice, thanks!
-(NSArray*) removeDuplicates:(NSArray*)inputArray{
NSMutableArray *arrayToClean = [NSMutableArray arrayWithArray:inputArray];
for (int i =0; i<[arrayToClean count]; i++) {
for (int j=(i+1); j < [arrayToClean count]; j++) {
if ([[arrayToClean objectAtIndex:i] isEqual:[arrayToClean
objectAtIndex:j]]) {
[arrayToClean removeObjectAtIndex:j];
j--;
}
}
}
NSArray *arrayToReturn = [NSArray arrayWithArray:arrayToClean];
return arrayToReturn;
}
NSSet will make this a lot easier:
-(NSArray *)removeDuplicates:(NSArray *)inputArray {
NSSet *unique = [NSSet setWithArray:inputArray];
return [unique allObjects];
}
Please note that a set has no guaranteed order. If you need the objects in the array to be in a specific order then you should sort the resulting array as needed.
It may also be appropriate to use an NSSet instead of the original array, then you don't need to worry about duplicates at all. But this depends on the other needs of your array.
Hey You can use another alternative for this.You can use the NSSet here for this task.
NSSet declares the programmatic interface for static sets of distinct objects
You can use sets as an alternative to arrays when the order of elements isn’t important and performance in testing whether an object is contained in the set is a consideration—while arrays are ordered, testing for membership is slower than with sets.
You Just need To call below method.
-(NSArray *)removeDuplicates:(NSArray *)inputArray {
NSSet *finalData = [NSSet setWithArray:inputArray];
return [finalData allObjects];
}
If really face any problem in above way of cleaning ducplicates then you can try another Alterantive.
-(NSArray *)removeDuplicates:(NSArray *)inputArray {
NSMutableArray *inputArray1=[NSMutableArray arrayWithArray:inputArray];
NSMutableArray *finalARray=[[NSMutableArray alloc]init];
for (id obj in inputArray1)
{
if (![finalARray containsObject:obj])
{
[finalARray addObject: obj];
}
NSLog(#"new array is %#",finalARray);
}
return finalARray;
}
I hope it may help you ...
Here is a helper function I had in a previous project to do the exact same thing
- (NSMutableArray *)removeDuplicates:(NSMutableArray *)sortedArray{
NSMutableSet* valuesAdded = [NSMutableSet set];
NSMutableArray* filteredArray = [[NSMutableArray alloc] init];
NSString* object;
/* Iterate over the array checking if the value is a member of the set. If its not add it
* to the set and to the returning array. If the value is already a member, skip over it.
*/
for (object in sortedArray){
if (![valuesAdded member:object]){
[valuesAdded addObject:object];
[filteredArray addObject:object];
}
}
return filteredArray;
}

Two-dimensional NSMutableArray of mutable arrays, but don't know how many I'll need

I have a large array (a few hundred objects), and I need to separate it into several arrays depending on an integer in the object, but I don't know how many arrays I'll need. I thought using a two-dimensional NSMutableArray would work, but if I do it as seen below, then when I empty the tempArray, it empties the array in fullArray as well. Is there another way to use a temporary, reusable array that, once it's been added to another array, it releases references to it.
- (void)createArray{
fullArray=[[NSMutableArray alloc]init];
NSMutableArray *tempArray=[[NSMutableArray alloc] init];
for(int j=0; j<numberOfGames; j++){
for(int i=0; i<[appDelegate.hiddenChars count]; i++){
Chars *charObj=[appDelegate.hiddenChars objectAtIndex:i];
if(charObj.gameID==j){
//NSLog(#"Match!");
[tempArray addObject:charObj];
}
}
[fullArray addObject:tempArray];
[tempArray removeAllObjects]; //this empties it from fullArray too
}
}
I can get a variable for how many rows and columns, but they're not static. I've tried using C arrays, but I won't be able to make a global array that way. I tried defining a global array and using "new" in create array, but Xcode says "new" is unrecognized.
I tried
id fullArray;//in global scope
fullArray=new id fullArray[rows][columns];//new and id throw exceptions, new unrecognized and id expects ";" before it.
My other thought is to create a singleton, but it seems like overkill for this problem. Surely there's a way to handle needing an unknown number of arrays?
I'll be using the arrays to populate a grouped tableview with multiple sections. Maybe I'm going about this all wrong?
Thanks for any help.
Change just about 2 lines and you've got it.
- (void)createArray{
fullArray=[[NSMutableArray alloc]init];
for(int j=0; j<numberOfGames; j++){
// inside loop
NSMutableArray *tempArray=[[NSMutableArray alloc] init];
for(int i=0; i<[appDelegate.hiddenChars count]; i++){
Chars *charObj=[appDelegate.hiddenChars objectAtIndex:i];
if(charObj.gameID==j){
//NSLog(#"Match!");
[tempArray addObject:charObj];
}
}
[fullArray addObject:tempArray];
[tempArray release]; // but fullArray still owns it
}
}

Array Allocation in Objective C++

I want to declare an array of numbers that is flexible in size in an obj C file
I am doing this:
long * arr = NULL;
a[0] = 0;
but this is giving bad_excess error
Can anyone help me out
also
long *arr = malloc(sizeof(long));
doesn't seem to help either
Why don't you do something like this,
NSMutableArray *numArray = [[NSMutableArray alloc] init];
This creates a array of objects. You can add any number of objects to it. Here you want to add long values. So use the following code,
[numArray addObject:[NSNumber numberWithLong:37];
[numArray addObject:[NSNumber numberWithLong:45];
[numArray addObject:[NSNumber numberWithLong:12];
NSMutableArray is flexible in size as you expected. You can add any number of objects.
If you want to get the number, you can do like the following,
long num1 = [[numArray objectAtIndex:0] longValue];
long num2 = [[numArray objectAtIndex:1] longValue];
You can also do as specified in the following link,
How to declare an array of floats as a class variable in Objective-C when the dimension is undefined at the class instantiation time?

Restrict Duplicate entry in NSArray

I have an array, which contains some duplicate entries.
Firstly, is there any way to restrict duplicate entries when data getting inserted?
Secondly, if an array already having duplicate values than in some other way, we can retrieve only unique values from that array, I heard about NSSet about this, but I have no idea how to use it.
Don't use an NSSet.
You can only insert elements upon creation and cannot change the elements contained after you have created it.
If you want to add and remove objects on the fly, you can use an NSMutableSet.
Here is a demo of how to use it both NSSet and NSMutableSet, then converting the NSSet back to an NSArray (incase you want to do that):
- (void) NSMutableSetPrintTest
{
NSMutableSet *mutableSet = [[NSMutableSet alloc] init];
NSLog(#"Adding 5 objects (3 are duplicates) to NSMutableSet");
NSString *firstString = #"Hello World";
[mutableSet addObject:firstString];
[mutableSet addObject:#"Hello World"];
[mutableSet addObject:#"Goodbye World"];
[mutableSet addObject:#"Goodbye World"];
[mutableSet addObject:#"Goodbye World"];
NSLog(#"NSMutableSet now contains %d objects:", [mutableSet count]);
int j = 0;
for (NSString *string in mutableSet) {
NSLog(#"%d: %# <%p>", j, string, string);
j++;
}
NSLog(#"Now, if we are done adding and removing things (and only want to check what is in the Set) we should convert to an NSSet for increased performance.");
NSSet *immutableSet = [NSSet setWithSet:mutableSet];
NSLog(#"NSSet now contains %d objects:", [immutableSet count]);
int i = 0;
for (NSString *string in immutableSet) {
NSLog(#"%d: %# <%p>", i, string, string);
i++;
}
[mutableSet release]; mutableSet = nil;
NSLog(#"Now, if we are done with the sets, we can convert them back to an NSArray:");
NSArray *array = [immutableSet allObjects];
NSLog(#"NSArray contains %d objects", [array count]);
int k = 0;
for (NSString *string in array) {
NSLog(#"%d: %# <%p>", k, string, string);
k++;
}
}
NSMutableSet is probably the most logical thing to use.
However, be warned that a set does not maintain order of its elements (since a set, by definition, is unordered).
If that's a problem for you, then you have a couple of options:
duplicate set functionality with an NSMutableArray by invoking containsObject: before every call to addObject: (doable, but potentially slow, since arrays have O(n) search time)
use another object.
If you go with the second option, I would recommend taking a look at the excellent CHDataStructures framework, which has a subclass of NSMutableSet called CHOrderedSet, which is a set that maintains insertion order. (And since it's a subclass, it has the exact same API as an NSMutableSet)
If you've heard about NSSet, did you read the documentation? The API is similar to NSArray and very straightforward. Just like NSArray vs. NSMutableArray, you would use NSMutableSet if you need on the fly membership tests.