How to declare class array in objective c - objective-c

I can declare NSMutableArray or NSArray but I want to declare class array. Let say user is a class so I can declare array as:
user* obj[10];
it is valid in Objective c, but I am not sure how I can set array capacity dynamically. Which we usually do with MutableArray as initWithCapacity:..
This is what I am doing with class:
user* objuser;
CustomOutput* output = [[CustomOutput alloc] init];
[objuser cutomSerialize:output];
NSMutableData* data = output.data;
But If I have array as:
NSMutableArray* aryUserObj;
I can't call cutomSerialize method from arryUserObj.
I want to Serialize all the userObj at ones and get a single NSData object.

The standard approach to serialize an array of objects is for you to define encodeWithCoder: and initWithCoder: in your User object:
#interface User: NSObject {
....
}
-(void)encodeWithCoder:(NSCoder*)coder ;
-(id)initWithCoder:(NSCoder*)coder;
#end
What you currently have in CustomSerialize should be in these methods.
Then, if you want to encode an object, you do
User* user=... ;
NSData* data=[NSKeyedArchiver archivedDataWithRootObject:user];
and decode it:
User* user=[NSKeyedUnarchiver unarchiveObjectWithData:data];
If you have an array of objects,
NSMutableArray* array=... ; // an array of users
NSData* data=[NSKeyedArchiver archivedDataWithRootObject:array];
and
NSArray* array=[NSKeyedUnarchiver unarchiveObjectWithData:data];
Iteration over array is done automatically.
Note also that you don't get the mutable array back, it's an immutable array.

NSMutableArray * users = [NSMutableArray array];
for (int i = 0; i < someNumber; ++i) {
User * aUser = [[User alloc] initWithStuff:someStuff];
[users addObject:aUser];
[aUser release];
}

Related

How to add new array element from another method in Objective-c?

I have some array( #private NSArray employees []; ) and method , which take string parameter( name of employees) and put this parameter in array. How I can do this with Objective-c?
You could do the following,
Create a property,
#property (nonatomic) NSMutableArray *array;
Initialise the array in your init method or somewhere else appropriate,
self.array = [[NSMutableArray alloc] init];
Your method could look something like this,
- (void)addEmployeeName:(NSString *)employeeName {
[self.array addObject:employeeName];
}
You can create a class Employee and use a type with your array.
For example:
NSArray<Employee*> * employees = [[NSArray alloc] init];
At this point, your method will be:
-(Employee *)createEmployee:(NSString *)name{
Employee *myEmpl = [[Employee alloc]init];
[myEmpl setName:name];
return myEmpl;
}
and you can add the object (of type Employee) in your array in this way:
[employees addObject:[self createEmployee]];
the same thing is possibile with an object of type NSString instead of Employee.
You can also avoid defining the type in your NSArray because Objective-C use the type inference

NSMutableArray with size of 9

I need to have an NSMutableArray with a constant count of 9 where I can make index-specific insertions and deletions. I know that array = [[NSMutableArray alloc] initWithCapacity:9]; will declare an array with a capacity of 9, but when you get the size of the array, it returns 0.
My first attempt at a solution was to declare an array with capacity 9 (see above) and then fill it with NSNull objects. This code crashes with the error
[NSMutableArray insertObjects:atIndexes:]: array argument is not an NSArray'
- (void) setBlankArray: (NSMutableArray*)array {
for (int i = 0; i < 9; i++) {
[array insertObjects:[NSNull null] atIndexes:i];
}
}
-(void) addCurrentTile: (TileView*)aTile {
[currentTurnTilesArray insertObject:aTile atIndex: aTile.getValue-1];
}
-(void) removeCurrentTile: (TileView*)aTile {
[currentTurnTilesArray removeObjectAtIndex: aTile.getValue-1];
}
Is there a better way to accomplish it?
Not sure what you are trying to accomplish or why, but your removeCurrentTile will break it, because it will reduce the size of the array by 1. What you need to do is wrap this array with a class that guards it such that it can never never never have any other number of elements than 9.
Personally, I think what you're trying to do is silly. If you know you will always have exactly 9 slots, then you should start with a normal array, not a mutable array. It is the objects at each index that you want to mutate - not the array itself. For example, if these things were to be strings, then you would make an immutable array of 9 NSMutableString objects:
NSArray* arr = #[
[NSMutableString string],
[NSMutableString string],
[NSMutableString string],
[NSMutableString string],
[NSMutableString string],
[NSMutableString string],
[NSMutableString string],
[NSMutableString string],
[NSMutableString string]
];
Now each string can be mutated into another value, but no strings can be added or removed such as to change the length of the array.
Of course that's just an example (using strings, I mean). For maximum flexibility, this would be an NSArray of nine NSMutableDictionary objects. Now every NSMutableDictionary can contain anything, or nothing. But the number of NSMutableDictionaries will always be exactly nine, because the array itself is immutable.
You're looking for insertObject:atIndex:, or more simply addObject:.
[[NSMutableArray alloc] initWithCapacity:9] does not create an array with 9 elements.
It creates an empty array initialized with enough memory to hold 9 objects.
The purpose of this method is to allocate that much memory at once as you declare, so you can add elements to this array and system has not to allocate memory every time. This is only for optimization.
NSMutableArray reference
I just read your question, and I think I understand exactly what you need. Here is the code:
Declare a property:
#property (nonatomic, retain) NSMutableArray *myArray;
Synthesize it:
#synthesize myArray = _myArray;
Overrride its getter like this:
- (NSMutableArray *)myArray
{
if (!_myArray)
{
_myArray = [[NSMutableArray alloc] initWithCapacity:9];
for (int i = 0; i < 9; i++)
{
[self.myArray addObject:[NSNull null]];
}
}
return _myArray;
}
The "setBlankArray" method will simly set the property to nil, and next time you call the getter of the array property it will get automatically initialized with exactly what you need:
- (void)setBlankArray:(NSMutableArray *)array
{
self.myArray = nil;
}
VERY IMPORTANT: Do not write this code:
for (int i = 0; i < 9; i++)
{
[self.myArray addObject:[NSNull null]];
}
in the method just mentioned as this will make the array to contain 18 elements.
Then write the other 2 methods:
// you can also change the parameter from "id" to "TileView *"
- (void)addCurrentTile:(id)sender
{
NSInteger tileIndex = 1; // replace 1 with ((TileView *) sender).getValue - 1
[self.myArray replaceObjectAtIndex:tileIndex
withObject:sender];
}
// you can also change the parameter from "id" to "TileView *"
- (void)removeCurrentTile:(id)sender
{
NSInteger tileIndex = 1; // replace 1 with ((TileView *) sender).getValue - 1
[self.myArray replaceObjectAtIndex:tileIndex
withObject:[NSNull null]];
}
But, DO NOT FORGET to replace "id" with "TileView *", and TO SET the value of tileIndex to "((TileView *) sender).getValue - 1".
Hope this all makes sense, and is helpful for you.
Best regards

property for ivar that points to two-dimensional array of pointers to NSStrings

I want to create a class that contains a dynamic, two-dimensional c-array of pointers to NSStrings. I know I can simulate a two-dimensional array using an NSArray containing multiple NSArrays, but if possible I'd like to do this using a traditional two-dimensional c-array. ARC won't allow a simple assignment of a pointer to an NSString to an element of a c-array unless you use "__unsafe_unretained":
#interface NumberStringsArray : NSObject
{
#public
NSString * __unsafe_unretained **_array;
}
To avoid memory leaks and to give an object in the class ownership of each NSString assigned to the c-array, I add a pointer to each NSString object to an NSMutableArray. In -(void)dealloc I free the memory acquired to create the two-dimensional c-array.
Here's my question: How do I declare a property based on the _array ivar so that I can refer to the i,j element of the array as "foobar.array[i][j]" rather than "foobar->array[i][j]"?
Later amplification: I did it in a very similar manner to the answerer except for the __bridge stuff. I don't know if that makes a difference. I allocate the two-dimensional array here:
self->_array = (NSString * __unsafe_unretained **)calloc(_columnCount, sizeof(void *));
if (!self->_array)
return nil;
for (UINT16 i = 0; i < _columnCount; i++)
{
self->_array[i] = (NSString * __unsafe_unretained *)calloc(_rowCount, sizeof(void *));
if (!self->_array[i])
{
for (UINT16 a = 0; a < _columnCount; a++)
if (self->_array[a])
free(self->_array[a]);
if (self->_array)
free(self->_array);
return nil;
}
}
I put pointers to the NSString objects into the array using substrings generated from a file of comma-separated values:
NSArray *numbers = [line componentsSeparatedByString: #","];
for (UINT16 i = 0; i < _columnCount; i++)
{
NSString *number = #"";
if (i < [numbers count])
number = [numbers objectAtIndex: i];
//
// save it in owners
//
[self.owners addObject: number];
self->_array[i][j] = number;
}
In -(void)dealloc I free all the memory:
-(void)dealloc
{
for (UINT16 i = 0; i < self.columnCount; i++)
if (self->_array[i])
free(self->_array[i]);
if (self->_array)
free(self->_array);
}
Declare this property:
#property (nonatomic) NSString * __unsafe_unretained **_array;
Then you can allocate the pointers to objects:
_array= (NSString * __unsafe_unretained **) malloc(M*sizeof(CFTypeRef) );
for(NSUInteger i=0; i<M;i++)
{
_array[i]= ((NSString * __unsafe_unretained *) malloc(N*sizeof(CFTypeRef) );
for(NSUInteger j=0; j<N;j++)
{
_array[i][j]= (__bridge NSString*) (__bridge_retained CFTypeRef) [[NSString alloc]initWithCString: "Hello" encoding: NSASCIIStringEncoding];
// I see that you got habit with C so you'll probably like this method
}
}
Then when you don't need it anymore, free the array:
for(NSUInteger i=0; i<M; i++)
{
for(NSUInteger j=0; j<N;j++)
{
CFTypeRef string=(__bridge_transfer CFTypeRef) _array[i][j];
}
free(_array[i]);
}
free(_array);
You can't because you can't declare a concrete object for an Objective-C class. So
NumberStringsArray object;
is not allowed.
You are forced to declare it as
NumberStringsArray *object = [[NumberStringsArray alloc] init.. ];
so you have to access to the ivar through the correct -> operator applied to pointers. Mind that the object.something in Objective-C is just a shorthand for [object something] while in standard C you would use . to access to fields of a concrete struct.
(Note: This addresses the creation/use of the property to access the data, not the way the data should be managed by conventional Objective-C storage management or by ARC. Thinking about that makes my head hurt.)
If you want a read-only C array to "look" like an Objective-C property, declare the property such as #property (readonly, nonatomic) char* myProp; and then, rather than using #synthesize, implement a getter for it along the lines of:
-(char**)myProp {
return myPropPointer;
// Or, if the array is allocated as a part of the instance --
return &myPropArray[0];
}

Add a tag to NSMutableArray

Is it possible to set a tag for an NSMutableArray? I have to somehow determine, in an array of arrays, the single array which needs to be rewritten, and if I could just set the tag to that inner array to 1 (or some other number), this would be extremely easy.
Example:
NSMutableArray* outerArray = [NSMutableArray new];
NSMutableArray* innerArray1 = [NSMutableArray new];
NSMutableArray* innerArray2 = [NSMutableArray new];
NSMutableArray* innerArray3 = [NSMutableArray new];
NSMutableArray* innerArray4 = [NSMutableArray new];
[outerArray addObject:innerArray1];
[outerArray addObject:innerArray2];
[outerArray addObject:innerArray3];
[outerArray addObject:innerArray4];
//now let's say innerArray1 needs to be rewritten
//I would like to be able to do this
[innerArray1 setTag:100];
//then later, when I need to determine which of the arrays inside outerArray
//needs to be rewritten, I can just do this
for(NSMutableArray* temp in outerArray) {
if(temp.tag == 100) {
//do what I need to do
}
}
But you can't use setTag: with NSMutableArrays. What would be a workaround?
Arrays are ordered collections, so why don't you just keep track of which index needs to be rewritten.
When something happens such that the array at index 0 (which, in your example, would be innerArray1) of outer array needs to be written, cache index 0 -- as a property if this routine needs to span across separate methods.
Then, when it comes time to do the rewrite, consult the cached index. Retrieve the array to be rewritten like this: NSArray *arrayToRewrite = [outerArray objectAtIndex:cachedIndexToRewrite]; Or access it directly: [[outerArray objectAtIndex:cachedIndexToRewrite] replaceObjectAtIndex:whatever withObject:whatever];
You could use an NSMutableDictionary instead. The "tag" would just be the key and the array would be the value.
Use associated objects. You can even add a category to NSMutableArray that would add a tag property to them.
#interface NSMutableArray (TagExtension)
#property (nonatomic, assign) NSInteger tag;
#end
#implementation NSMutableArray (TagExtension)
#dynamic tag;
static char TagExtensionKey;
-(NSInteger)tag {
NSNumber *ourTag = (NSNumber *)objc_getAssociatedObject(self, &TagExtensionKey);
if( ourTag ) {
return( [ourTag integerValue] );
}
return(0);
}
-(void)setTag:(NSInteger)newTag {
objc_setAssociatedObject(self, &TagExtensionKey, [NSNumber numberWithInteger:newTag], OBJC_ASSOCIATION_RETAIN);
}
#end
See also: How to add properties to NSMutableArray via category extension?
Not sure why a dictionary is a bad idea hereā€¦ as alternatives, you can:
remember the index
or if each entry is a unique array, you can simply refer to it by pointer:
NSArray * tagged = theArray;
for (NSMutableArray * at in outerArray) {
if (tagged == at) {
//do what I need to do
}
}
Make your inner arrays class variables. Then you can just access them as:
for(NSMutableArray* temp in outerArray) {
if(temp == self.innerArray1) {
//do what I need to do
}

Removing duplicates from array based on a property in Objective-C

I have an array with custom objects. Each array item has a field named "name". Now I want to remove duplicate entries based on this name value.
How should I go about achieving this?
I do not know of any standard way to to do this provided by the frameworks. So you will have to do it in code. Something like this should be doable:
NSArray* originalArray = ... // However you fetch it
NSMutableSet* existingNames = [NSMutableSet set];
NSMutableArray* filteredArray = [NSMutableArray array];
for (id object in originalArray) {
if (![existingNames containsObject:[object name]]) {
[existingNames addObject:[object name]];
[filteredArray addObject:object];
}
}
You might have to actually write this filtering method yourself:
#interface NSArray (CustomFiltering)
#end
#implementation NSArray (CustomFiltering)
- (NSArray *) filterObjectsByKey:(NSString *) key {
NSMutableSet *tempValues = [[NSMutableSet alloc] init];
NSMutableArray *ret = [NSMutableArray array];
for(id obj in self) {
if(! [tempValues containsObject:[obj valueForKey:key]]) {
[tempValues addObject:[obj valueForKey:key]];
[ret addObject:obj];
}
}
[tempValues release];
return ret;
}
#end
I know this is an old question but here is another possibility, depending on what you need.
Apple does provide a way to do this -- Key-Value Coding Collection Operators.
Object operators let you act on a collection. In this case, you want:
#distinctUnionOfObjects
The #distinctUnionOfObjects operator returns an array containing the distinct objects in the property specified by the key path to the right of the operator.
NSArray *distinctArray = [arrayWithDuplicates valueForKeyPath:#"#distinctUnionOfObjects.name"];
In your case, though, you want the whole object. So what you'd have to do is two-fold:
1) Use #distinctUnionOfArrays instead. E.g. If you had these custom objects coming from other collections, use #distinctUnionOfArray.myCollectionOfObjects
2) Implement isEqual: on those objects to return if their .name's are equal
I'm going to get flak for this...
You can convert your array into a dictionary. Not sure how efficient this is, depends on the implementation and comparison call, but it does use a hash map.
//Get unique entries
NSArray *myArray = #[#"Hello", #"World", #"Hello"];
NSDictionary *uniq = [NSDictionary dictionaryWithObjects:myArray forKeys:myArray];
NSLog(#"%#", uniq.allKeys);
*Note, this may change the order of your array.
If you'd like your custom NSObject subclasses to be considered equal when their names are equal you may implement isEqual: and hash. This will allow you to add of the objects to an NSSet/NSMutableSet (a set of distinct objects).
You may then easily create a sorted NSArray by using NSSet's sortedArrayUsingDescriptors:method.
MikeAsh wrote a pretty solid piece about implementing custom equality: Friday Q&A 2010-06-18: Implementing Equality and Hashing
If you are worried about the order
NSArray * newArray =
[[NSOrderedSet orderedSetWithArray:oldArray] array]; **// iOS 5.0 and later**
It is quite simple in one line
NSArray *duplicateList = ...
If you don't care about elements order then (unordered)
NSArray *withoutDUP1 = [[NSSet setWithArray:duplicateList] allObjects];
Keep the elements in order then (ordered)
NSArray *withoutDUP2 = [[NSOrderedSet orderedSetWithArray:duplicateList] array];
Implement isEqual to make your objects comparable:
#interface SomeObject (Equality)
#end
#implementation SomeObject (Equality)
- (BOOL)isEqual:(SomeObject*)other
{
return self.hash == other.hash;
}
- (NSUInteger)hash
{
return self.name;///your case
}
#end
How to use:
- (NSArray*)distinctObjectsFromArray:(NSArray*)array
{
return [array valueForKeyPath:#"#distinctUnionOfObjects.self"];
}