__unsafe_unretained in struct - objective-c

Let say I have a struct in which I declare like so:
struct myStruct
{
NSString *aString;
}
The above gives error.
I can, however, fix the error by:
struct myStruct
{
__unsafe_unretained NSString *aString;
}
It silences the error, but will crash at runtime, because I suppose aString is immediately released.
I have tried __strong instead but it won't compile.
Is there any other way I can store an object within the struct and use it properly?

You can create a new object and use this as a pointer to a struct (as this is what a Objective C object is). So if you create a subclass of NSObject with instance variables that you require you can treat it exactly like a pointer to a structure (once you have initialised it). i.e.
myObj = [[myObjClass alloc] init];
myObj->instanceVariable1 = #"myString";
As mentioned in the comments below you need to declare the variables in the interface like this:
#interface myObjStruct : NSObject
{
#public
NSString *instanceVariable1;
}
With an NSString you can use a CFStringRef instead, or cast your NSString * to a CFString and retain it with a CFRetain(), or use CFBridgingRetain to get the incremented retain count immediately. You can do this with any type that is toll free bridged from a CF type (such as CFArray CFDictionary).
struct testStruct {
CFStringRef str;
};
- (void)aMethod
{
NSString *string = #"Hello struct";
struct testStruct test = {
CFBridgingRetain(string),
};
}
You now have ownership of the string, and will need to call CFRelease on the test.str at some point to not leak memory. To get a NSString back you cast it like this NSString *string = (__bridge NSString *)test.str;.
The above code has incremented the retain count of the string object. It's possible to get this to work for any object like this:
struct testStruct {
__unsafe_unretained AnyObj *obj;
};
- (void)aMethod
AnyObj *aObj = [[AnyObj alloc] init];
CFBridgingRetain(aObj); \\increment the retain count.
struct testStruct test = {
aObj,
};
aObj = nil;
NSLog(#"%#", aObj);
}
To release this object later you would need to do CFRelease((__bridge CFTypeRef)(test.obj));. Note that if you remove the CFBridgingRetain(aObj); this code will probably crash.
You could also try having a play with id objc_retain(id value); Although to use this you will need to manually include the arc.h header see How to import objc_retainAutoreleasedReturnValue? you would use this to increment the retain value much like the code above but without the need for casting. You'd also have to use the equivalent release function.

Toll-Free Bridged Types
__bridge transfers a pointer between Objective-C and Core Foundation with no transfer of ownership.
__bridge_retained or CFBridgingRetain casts an Objective-C pointer to a Core Foundation pointer and also transfers ownership to you. You are
responsible for calling CFRelease or a related function to relinquish
ownership of the object.
__bridge_transfer or CFBridgingRelease moves a non-Objective-C pointer to Objective-C and also transfers ownership to ARC. ARC is responsible
for relinquishing ownership of the object.
Example (not recommend)
It seems __bridge_retained, __bridge_transfer don't allow ownership transfer to/from same type. So I used additional __bridge for type casting.
I've test confirmed NSString objects are released without leaks.
#define TEST_COUNT 10000
struct myStruct
{
NSString* __unsafe_unretained aString;
};
static struct myStruct* myArray = NULL;
static void allocString()
{
myArray = (struct myStruct*) malloc(sizeof(struct myStruct) * TEST_COUNT);
for (int i=0; i<TEST_COUNT; ++i)
{
NSString* v = [[NSString alloc] initWithFormat:#"%d", i];
myArray[i].aString = (__bridge NSString*)(__bridge_retained void*) v;
}
}
static void freeString()
{
if (myArray)
{
for (int i=0; i<TEST_COUNT; ++i)
{
if (myArray[i].aString)
{
NSString* v = (__bridge_transfer NSString*) (__bridge void*) myArray[i].aString;
v = nil;
}
}
free(myArray);
}
}

Related

Memory Management Objective-C

I don't understand why memory consumption increases and never gets released (the project is using ARC) when performing the following operations in my program (please bear with me, I'm at a basic level with plain C):
Simplified: somewhere in my program (AppDelegate for example) I call a macro which basically is a C function with variable parameters which calls other C functions that are returning some NSStrings.
These are defined and implemented in an Objective-C style class and are used together with a singleton object.
Header:
#interface MyClass : NSObject
#end
void func_1(aTypeDef paramType, NSString *input, ...);
void* func_2(NSString *arg1, NSString *arg2, NSString *arg3);
NSString* string_func_1 (void);
NSString* string_func_2 (int anInt);
NSString* string_func_3 (const char *aString);
#define F2_MACRO func_2( \
string_func_1(), \
string_func_2(anINT), \
string_func_3(aSTRING), \
)
#define F1_MACRO(input, ...) func_1(A_TYPE, input, ##__VA_ARGS__, F2_MACRO)
Implementation:
#import "MyClass.h"
static NSString *STRING_1;
static NSString *STRING_2;
static NSString *STRING_3;
#implementation MyClass
void func_1(aTypeDef paramType, NSString *input, ...) {
va_list args;
va_start(args, input);
NSString *output = [[NSString alloc] initWithFormat:input arguments:args];
fputs([output UTF8String], stdout);
va_end(args);
}
void* func_2(NSString *arg1, NSString *arg2, NSString *arg3) {
STRING_1 = arg1;
STRING_2 = arg2;
STRING_3 = arg3;
return NULL;
}
NSString* string_func_1 (void) {
return [NSString stringWithFormat:#"aString"];
}
NSString* string_func_2 (int anInt) {
return [NSString stringWithFormat:#"%d",anInt];
}
NSString* string_func_3 (const char *aString) {
return [NSString stringWithUTF8String:aString];
}
#end
Every time I call the F1_MACRO() in another Objective-C class like AppDelegate memory usage increases every time the string_func_1, string_func_2, string_func_3 return.
I'm sure that my logic and implementation are flawed and I'll appreciate any help.
func_1() is creating a non-autoreleased object.
• If you are using Automatic Reference Counting (ARC), not autoreleasing the object is fine, however it can still lead to apparent memory accretion. Specifically, if you don't have an explicitly #autoreleasepool{} or are not running an event loop on the thread that is calling that function, then the autoreleased object will never be released.
• If you aren't using ARC, then that is a straight up leak. Add [output release]; at the end of the func_1() function.

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;

Get property name as a string

I need a way to pass a property and get the name assigned to it. Any suggestions?
#property (nonatomic, retain) MyObject *crazyObject;
NSString *str = SOME_WAY_TO_GET_PROPERTY_NAME(crazyObject);
// Above method should return #"crazyObject"
You can try this:
unsigned int propertyCount = 0;
objc_property_t * properties = class_copyPropertyList([self class], &propertyCount);
NSMutableArray * propertyNames = [NSMutableArray array];
for (unsigned int i = 0; i < propertyCount; ++i) {
objc_property_t property = properties[i];
const char * name = property_getName(property);
[propertyNames addObject:[NSString stringWithUTF8String:name]];
}
free(properties);
NSLog(#"Names: %#", propertyNames);
It's as simple as this...expanding upon what Chuck already mentioned:
#ifndef STR_PROP
#define STR_PROP( prop ) NSStringFromSelector(#selector(prop))
#endif
You then use it like so:
NSString *strProp = STR_PROP(myProperty);
Background
Keep in mind that properties are really just, to quote Apple, "a syntactical shorthand for declaring a class’s accessor methods." In fact, by itself, the #property declaration doesn't even work. Your #synthesize statement translates the #property into the equivalent of two methods:
- (void)setCrazyObject:(MyObject *)something;
- (MyObject *)crazyObject;
Which one is used depends on the context surrounding your self.crazyObject. (#synthesize also creates a matching instance variable if you didn't do it yourself.) The offshoot of all this is that you can't really translate to and from a property with one single method.
Proposed Solution
You can use what Apple already provides:
NSString *foo = NSStringFromSelector(#selector(myClassProperty));
Or do something custom:
Given that self.crazyObject really translates to either [self crazyObject] or [self setCrazyObject:foo] by the time your code is running, ou'll probably need two methods, like:
- (NSString *)setterStringForProperty:(SEL)prop;
- (NSString *)getterStringForProperty:(SEL)prop;
You might then want at least 2 companion methods such as:
- (SEL)setterForPropertyName:(NSString *)propString;
- (SEL)getterForPropertyName:(NSString *)propString;
Within these methods, you can use the Foundation functions NSStringFromSelector and NSSelectorFromString to convert back and forth between SEL and NSString. Use whatever string manipulations you like to convert back and forth between your setter string (setCrazyObject) and your property name (crazyObject).
A complete solution is hard to provide without knowing the exact use case, but hopefully this provides some more clues for anyone trying to accomplish something similar. There might even be some useful things made possible by combining this approach with Oscar's answer.
Here is a function that returns the name of an ivar, so basically it not only returns the properties but any ivar of the class. I haven't found a way to get the property directly so I used the ivar trick.
#import <objc/objc.h>
/// -----
- (NSString *)nameOfIvar:(id)ivarPtr
{
NSString *name = nil;
uint32_t ivarCount;
Ivar *ivars = class_copyIvarList([self class], &ivarCount);
if(ivars)
{
for(uint32_t i=0; i<ivarCount; i++)
{
Ivar ivar = ivars[i];
id pointer = object_getIvar(self, ivar);
if(pointer == ivarPtr)
{
name = [NSString stringWithUTF8String:ivar_getName(ivar)];
break;
}
}
free(ivars);
}
return name;
}
After searching and debugging i find solution for me...
Added #import <objc/runtime.h>
Methods object_getIvar(id obj, Ivar ivar) send bad access and app crashes. i modify some code and it worked great:
+(NSString*)stringWithProperty:(id)property withClass:(id)controller
{
NSString *name = nil;
uint32_t ivarCount;
Ivar *ivars = class_copyIvarList([controller class], &ivarCount);
if(ivars)
{
for(uint32_t i=0; i<ivarCount; i++)
{
Ivar ivar = ivars[i];
name = [NSString stringWithUTF8String:ivar_getName(ivar)];
if ([controller valueForKey:name] == property)
{
break;
}
}
free(ivars);
}
return name;
}
Modifying the solution, it works when your object is allocated already, otherwise it returns nil:-
NSString * NSStringFromProperty(NSObject* property, NSObject* class)
{
unsigned int propertyCount = 0;
objc_property_t * properties = class_copyPropertyList([class class], &propertyCount);
NSString *name = nil;
for (unsigned int i = 0; i < propertyCount; ++i)
{
name = [NSString stringWithUTF8String:property_getName(properties[i])];
NSObject *object = [class valueForKey:name];
if (object != nil && object == property)
{
break;
}
else
{
name = nil;
}
}
free(properties);
return name;
}
You can use
NSString *str = NSStringFromSelector(#selector(crazyObject));
The good thing about this approach is that:
Xcode will autocomplete word crazyObject for you.
When later on you will change the property name from crazyObject to myCrazyObject, Xcode will add a warning saying "unrecognized selector!" -- pretty good for debugging.
I use this method so often, that I even created a function, which allows to write less letters:
NSString * __nonnull sfs(SEL __nonnull theSelector)
{
if (!theSelector)
{
abort();
}
return NSStringFromSelector(theSelector);
}
Now your final solution can look like this:
NSString *str = sfs(#selector(crazyObject));
From Get property name as string, without using the runtime reference library, just define:
#define propertyKeyPath(property) (#""#property)
#define propertyKeyPathLastComponent(property) [[(#""#property) componentsSeparatedByString:#"."] lastObject]
And then you can do something like this:
NSLog(#"%#", propertyKeyPathLastComponent(appleStore.storeLocation.street)); //result: street
You may check my approach at Gist to get the string for a property with autocompletion and compile-time check.
How to use:
Get the property name for a class:
#interface AnyClass : NSObject
#property (strong) NSData *data;
#end
// == My approach ==
// C string for a class
PropertyNameForClass(AnyClass, data); // ==> "data"
// NSString for a class
PropertyStringForClass(AnyClass, data); // ==> #"data"
// Bad approach (no autocompletion; no compile-time check):
NSString *propertyName = #"data";
Get the property name for a protocol:
#protocol AnyProtocol
#property (strong) NSDate *date;
#end
// C string for a protocol
PropertyNameForProtocol(AnyProtocol, date); // ==> "date"
// NSString for a protocol
PropertyStringForProtocol(AnyProtocol, date); // ==> #"date"
Unconventional, hacky, ugly, late, but... as strong-named as it gets and works like a charm:
#define SOME_WAY_TO_GET_PROPERTY_NAME(p) p == p ? [[[[[[[NSString alloc] initWithCString:#p encoding:NSUTF8StringEncoding] componentsSeparatedByString:#"."] lastObject] componentsSeparatedByString:#" "] lastObject] stringByReplacingOccurrencesOfString:#"]" withString:#""] : #""
Sample usage:
NSLog(SOME_WAY_TO_GET_PROPERTY_NAME(self.customer.surname)); // surname
NSLog(SOME_WAY_TO_GET_PROPERTY_NAME([[self customer] birthDate])); // birthDate
...

Passing An Array By Reference In Objective-C

I would like to pass a NSMutableArray by reference so that it can be altered by another method. What would be the correct syntax for this?
Thanks,
Objective-C objects are always passed by reference (using pointers) - you can't pass them by value.
I.e. the following is fine:
- (void)mutateArray:(NSMutableArray*)array {
// alter array ...
}
... and can be e.g. invoked like this:
NSMutableArray *array = ...;
[self mutateArray:array];
There is also the possibility of passing a pointer by reference:
- (void)newArray:(NSMutableArray **)array;
In that case array is used as an out-parameter - you pass a reference to a pointer to receive an instance:
- (void)newArray:(NSMutableArray **)array {
*array = [[NSMutableArray alloc] init];
}
... which could be called like so:
NSMutableArray *array = nil;
[self newArray:&array];
Using out-parameters is usually only seen if the return-value is already used and additional information has to be returned. An example would be error-information as dreamlax noted.
In addition to Georg Fritzche's answer, it may be worth noting that some methods expect to be given the address of an object pointer. For example:
NSError *anError; // points to garbage now
NSStringEncoding enc;
NSString *aString = [NSString stringWithContentsOfFile:#"/some/file.txt"
usedEncoding:&enc
error:&anError];
if (aString == nil)
{
// anError now points to an initialised NSError object.
}
It gets tricky because some documented methods require you to release objects obtained in this manner, and some don't (for an example of one that does require explicit releasing, see NSPropertyListSerialization).
As Georg Fritzsche said NSMutableArray passed be reference automatically, but not the NSArray. The best option is too look at the code bellow:
void mutateImmutableArray(NSArray *array);
void mutateMutableArray(NSMutableArray *array);
void mutateImmutableArrayByRef(NSArray **array);
void mutateMutableArrayByRef(NSMutableArray **array);
int main(int argc, const char * argv[]) {
#autoreleasepool {
//Change immutable array in method that expects immutable array
NSArray *immutable = #[#1,#2,#3];
mutateImmutableArray(immutable);
NSLog(#"After 1: %#",immutable); // 1,2,3
//Change mutable array in method that expects immutable array
NSMutableArray *mutable = [#[#1,#2,#3]mutableCopy];
mutateImmutableArray(mutable);
NSLog(#"After 2: %#",mutable); //1,2,3
//Change mutable array in method that expects mutable array
mutable = [#[#1,#2,#3]mutableCopy];
mutateMutableArray(mutable);
NSLog(#"After 3: %#",mutable); //1,2,3, Four
//Change immutable array in method that expects immutable array by reference
immutable = #[#1,#2,#3];
mutateImmutableArrayByRef(&immutable);
NSLog(#"After 4: %#",immutable); //4,5,6
//Change mutable array in method that expects mutable array by reference
mutable = [#[#1,#2,#3]mutableCopy];
mutateMutableArrayByRef(&mutable);
NSLog(#"After 5: %#",mutable); //1,2,3, Four
}
return 0;
}
void mutateImmutableArray(NSArray *array)
{
array = #[#4,#5,#6];
}
void mutateImmutableArrayByRef(NSArray **array)
{
*array = #[#4,#5,#6];
}
void mutateMutableArray(NSMutableArray *array)
{
[array addObject:#"Four"];
}
void mutateMutableArrayByRef(NSMutableArray **array)
{
[*array addObject:#"Four"];
}