C array of Objective C objects - objective-c

I'm trying to create a C array of objective C NSStrings using malloc. I'm not doing it right, but I don't think I'm far off. Maybe someone can point me in the right direction.
Let's say we want 5 strings in our array for the sake of argument.
Interface:
#interface someObject : NSObject {
NSString **ourArray;
}
#property () NSString **ourArray;
#end
Implementation:
#implementation someObject
#synthesize ourArray;
-(id)init {
if((self = [super init])) {
self->ourArray = malloc(5 * sizeof(NSString *));
}
return self;
}
-(NSString *)getStringAtPos3 {
if(self.ourArray[3] == nil) {
self.ourArray[3] = #"a string";
}
return self.ourArray[3];
}
#end
When I set a breakpoint in getStringAtPos3 it doesn't see the array element as nil so it never goes into the if statement.

mallocing an array of pointers is done as follows:
self->ourArray = malloc(5 * sizeof(NSString *));
if (self->ourArray == NULL)
/* handle error */
for (int i=0; i<5; i++)
self->ourArray[i] = nil;
malloc doesn't make guarantees about the contents of the returned buffer, so set everything to nil explicitly. calloc won't help you here, as a zero pattern and nil/NULL aren't the same thing.
Edit: even though zero and null may be the same on i386 and arm, they are not the same conceptually, just like NULL and nil are strictly not the same. Preferably, define something like
void *allocStringPtrs(size_t n)
{
void *p = malloc(sizeof(NSString *));
if (p == NULL)
// throw an exception
for (size_t i=0; i<n; i++)
p[i] = nil;
return p;
}

One issue is this:
self->ourArray = malloc(5 * sizeof(NSString *)); // notice the sizeof()

I figured out the problem - I should have been using calloc, not malloc. While malloc simply allocates the memory, calloc
contiguously allocates enough space for count objects that are size bytes of memory each and returns a pointer to the allocated memory. The allocated memory is filled with bytes of value zero.
This means you get an array of nil objects essentially as in objective c 0x0 is the nil object.

Related

C-style Multidimensional Array in ARC Objective-C

I'm trying to implement an n x n multidimensional array of ints in Objective-C, and because using NSMutableArray seems to be too much of an overhead I decided to implement it using only C's malloc and free. My question is, is the code below correct (no memory leaks) under ARC Objective-C?
#interface TwoDimensionalArray
{
int **array;
int size;
}
#end
#implementation TwoDimensionalArray
- (id)initWithSize: (int)s
{
if(self = [super init])
{
size = s;
array = malloc(sizeof(int*) * size);
for(int i = 0; i < size; i++)
{
array[i] = malloc(sizeof(int) * size);
for (int j = 0; j < size; j++)
{
array[i][j] = 0;
}
}
}
return self
}
- (id)init
{
return [self initWithSize:1];
}
- (void)dealloc
{
for(int i = 0; i < size; i++)
{
free(array[i]);
array[i] = nil;
}
free(array);
array = nil;
}
#end
If this is not correct, or if you think there is a definitely better way to do it in Objective-C without doing mallocs, please tell me. Thanks.
ARC implements automatic memory management for Objective-C objects and blocks, but does not
automate malloc/free.
(References: Clang/ARC documentation: General,
ARC Release Notes: FAQ.)
So your question is unrelated to ARC: Everything you malloc() must be
free()'d (and dealloc is good place to do so). From the first look your code looks OK.
(Small remarks: Zeroing the array pointers in dealloc is not necessary, but
NULL would be the appropriate pointer value to assign, nil is meant for Objective-C objects.)
I do not know how much overhead using Objective-C collections such as NSMutableArray
would cause, that should be tested (as already said in the comments) by profiling.

Why would a function defined in the same class be considered undeclared? How to declare it properly?

I'm getting the error "undeclared identifier" on the commented line:
- (BOOL) isInIntArray:(NSInteger[])array theElem:(int)elem{
int i = 0;
NSInteger sizeOfArray = (sizeof array) / (sizeof array[0]);
while(i < sizeOfArray){
if(array[i] == elem){
return TRUE;
}
i++;
}
return FALSE;
}
- (int)getNextUnusedID{
int i = rand()%34;
while ([isInIntArray:idsUsed theElem:i]) { //here: Use of undeclared identifier 'isInIntArray'
i = rand()%34;
}
return i;
}
I really don't understand why, they are in the same .m file.
Why would that be?
Also, this code:
NSInteger sizeOfArray = (sizeof array) / (sizeof array[0]);
is giving me the warning:
Sizeof on array function will return Sizeof 'NSInteger *' (aka: 'int *') instead of 'NSInteger[]'"
How should I properly determine the size of an array?
It looks like you've missed out self from this line
while ([isInIntArray:idsUsed theElem:i])
This should be:
while ([self isInIntArray:idsUsed theElem:i])
As #CaptainRedmuff pointed out, you are missing the target object in method invocation, that is self.
//[object methodParam:x param:y];
[self isInIntArray:idsUsed theElem:i];
To your second Q. In C language you cannot determine the size of an array. That's why they are not used, since we have objects for this. I recommend you to use these:
NSMutableArray *array = [[NSMutableArray alloc] init]; // to create array
array[0] = #42; // to set value at index, `#` creates objects, in this case NSNumber
[array insertObject:#42 atindex:0]; // equivalent to the above
NSInteger integer = array[0].integerValue; // get the value, call integerMethod to get plain int
integer = [[array objectAtIndex:0] integerValue]; // equivalent to the above
[array containsObject:#42]; // test if given object is in the array
[array indexOfObject:#42]; // get index of object from array, NSNotFound if not found
array.count; // to get the number of objects
Important: These arrays have variable size and they are not limited! But you can access elements only at indexes 0..(n-1) (where n in number of objects) and you can set values only for indexes 0..n.
In other words, you can not do array[3] = #42; for empty array, you need to fill first 3 positions first (indexes 0, 1 and 2).
write this in .h file (declare the function)
- (BOOL) isInIntArray:(NSInteger[])array theElem:(int)elem;
and call the method using following way
while ([self isInIntArray:idsUsed theElem:i]) { //here: Use of undeclared identifier 'isInIntArray'
i = rand()%34;
}

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];
}

'Assigning to 'id' from incompatible type'

I'm implementing a objective C wrapper for Box2d (which is written in c++). The b2Body keeps a reference to its wrapper B2Body in its userData field. GetUserData returns a void*. I'm now implementing fast iteration for getting the B2Bodies out of the B2World.
I get an 'Assigning to 'id' from incompatible type 'B2Body *' error at the line indicated below. Why?
#import "B2Body.h"
#import "B2World.h"
#import "Box2d.h"
#implementation B2World
-(id) initWithGravity:(struct B2Vec2) g
{
if (self = [super init])
{
b2Vec2 *gPrim = (b2Vec2*)&g;
_world = new b2World(*gPrim);
}
return self;
}
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained [])buffer count:(NSUInteger)len;
{
if(state->state == 0)
{
state->mutationsPtr = (unsigned long *)self;
state->extra[0] = (long) ((b2World*)_world)->GetBodyList();
state->state = 1;
}
// pull the box2d body out of extra[0]
b2Body *b = (b2Body*)state->extra[0];
// if it's nil then we're done enumerating, return 0 to end
if(b == nil)
{
return nil;
}
// otherwise, point itemsPtr at the node's value
state->itemsPtr = ((B2Body*)b->GetUserData()); // ERROR
state->extra[0] = (long)b->GetNext();
// we're returning exactly one item
return 1;
}
`
B2Body.h looks like this:
#import
#interface B2Body : NSObject
{
int f;
}
-(id) init;
#end
NSFastEnumerationState is a C structure, and the itemsPtr field is:
id __unsafe_unretained *itemsPtr;
In earlier versions, the __unsafe_unretained specifier was obviously missing.
Note, that the field itemsPtr is a pointer-to-id. Since id is essentially a pointer, itemsPtr is a pointer to an object pointer. Actually, this field is what holds the array of objects that allows the fast enumeration. Basically, it trolls through this array of object pointers.
Since I know nothing about Box2d, that's about all I can say. Assuming b->GetUserData() returns a pointer to an array of objects, you should be able to do this:
state->itemsPtr = (__unsafe_unretained id *)b->GetUserData();
While a bit dated, Mike Ash's article is still a great source for implementing fast enumeration.
EDIT
Just noticed that you are returning a single object. So, I assume GetUserData just returns a single object pointer. Since you need to return a pointer to object pointers, you would need to do something like this:
id object = (__bridge id)b->GetUserData();
state->itemsPtr = &object;
However, that stack object will be gone once you return from this method, which is why you are passed a stack buffer you can use. Thus, you should probably stuff that single pointer into the provided stack buffer:
*buffer = (__bridge id)b->GetUserData()
state->itemsPtr = buffer;

Recursive Blocks in Objective-C leaking in ARC

So I'm using recursive blocks. I understand that for a block to be recursive it needs to be preceded by the __block keyword, and it must be copied so it can be put on the heap. However, when I do this, it is showing up as a leak in Instruments. Does anybody know why or how I can get around it?
Please note in the code below I've got references to a lot of other blocks, but none of them are recursive.
__block NSDecimalNumber *(^ProcessElementStack)(LinkedList *, NSString *) = [^NSDecimalNumber *(LinkedList *cformula, NSString *function){
LinkedList *list = [[LinkedList alloc] init];
NSDictionary *dict;
FormulaType type;
while (cformula.count > 0) {
dict = cformula.pop;
type = [[dict objectForKey:#"type"] intValue];
if (type == formulaOperandOpenParen || type == formulaListOperand || type == formulaOpenParen) [list add:ProcessElementStack(cformula, [dict objectForKey:#"name"])];
else if (type == formulaField || type == formulaConstant) [list add:NumberForDict(dict)];
else if (type == formulaOperand) [list add:[dict objectForKey:#"name"]];
else if (type == formulaCloseParen) {
if (function){
if ([function isEqualToString:#"AVG("]) return Average(list);
if ([function isEqualToString:#"MIN("]) return Minimum(list);
if ([function isEqualToString:#"MAX("]) return Maximum(list);
if ([function isEqualToString:#"SQRT("]) return SquareRoot(list);
if ([function isEqualToString:#"ABS("]) return EvaluateStack(list).absoluteValue;
return EvaluateStack(list);
} else break;
}
}
return EvaluateStack(list);
} copy];
NSDecimalNumber *number = ProcessElementStack([formula copy], nil);
UPDATE
So in my own research I've discovered that the problem apparently does have to do with the references to the other blocks this block uses. If I do something simple like this, it doesn't leak:
__block void (^LeakingBlock)(int) = [^(int i){
i++;
if (i < 100) LeakingBlock(i);
} copy];
LeakingBlock(1);
However, if I add a another block in this, it does leak:
void (^Log)(int) = ^(int i){
NSLog(#"log sub %i", i);
};
__block void (^LeakingBlock)(int) = [^(int i){
Log(i);
i++;
if (i < 100) LeakingBlock(i);
} copy];
LeakingBlock(1);
I've tried using the __block keyword for Log() and also tried copying it, but it still leaks. Any ideas?
UPDATE 2
I found a way to prevent the leak, but it's a bit onerous. If I convert the passed in block to a weak id, and then cast the weak id back into a the block type, I can prevent the leak.
void (^Log)(int) = ^(int i){
NSLog(#"log sub %i", i);
};
__weak id WeakLogID = Log;
__block void (^LeakingBlock)(int) = [^(int i){
void (^WeakLog)(int) = WeakLogID;
WeakLog(i);
if (i < 100) LeakingBlock(++i);
} copy];
LeakingBlock(1);
Surely there's a better way?
Ok, I found the answer on my own...but thanks to those who tried to help.
If you're referencing/using other blocks in a recursive block, you must pass them in as weak variables. Of course, __weak only applies to block pointer types, so you must typedef them first. Here's the final solution:
typedef void (^IntBlock)(int);
IntBlock __weak Log = ^(int i){
NSLog(#"log sub %i", i);
};
__block void (^LeakingBlock)(int) = ^(int i){
Log(i);
if (i < 100) LeakingBlock(++i);
};
LeakingBlock(1);
The above code doesn't leak.
Aaron,
As your code appears to be single threaded, why are you copying the block? If you don't copy the block, you don't have a leak.
Andrew
Without further context information, I can say this:
You are leaking that block because you are copying it and not releasing it elsewhere. You need to copy it to move it to the heap, that's ok. But the way you've chosen is not entirely ok.
A correct way to do it is to store it as some object instance variable, copy it, and then release it inside dealloc. At least, that's a way to do it without leaking.