Suppose, under ARC, you could declare a struct like this:
typedef struct {
__strong NSObject *someObject;
int someInteger;
} MyStruct;
Then you might write code like this:
MyStruct *thing = malloc(sizeof(MyStruct));
Problem: malloc
doesn't zero-fill the memory it returns. So thing->someObject
is some random value - not necessarily NULL. Then you assign a value to it like this:
thing->someObject = [[NSObject alloc] init];
Under the covers, ARC will turn that into code like this:
NSObject *temporary = [[NSObject alloc] init];
[thing->someObject release];
thing->someObject = temporary;
The problem here is that your program just sent release
to some random value! Your app will probably crash at this point.
You might say that ARC should recognize the call to malloc
and take care of setting someObject
to NULL to prevent this. The problem is that malloc
might be wrapped in some other function, like this:
void *myAllocate(size_t size) {
void *p = malloc(size);
if (!p) {
// malloc failed. Try to free up some memory.
clearCaches();
p = malloc(size);
}
return p;
}
OK, now ARC has to know about your myAllocate
function too... and that might be inside some static library that you got as a binary.
Your app might even have its own memory allocators that recycle old allocations without using free
and malloc
every time. So even changing malloc
to zero-fill the memory before returning it would not work. ARC would have to know about any custom allocators in your program.
It would be very, very hard to make this work reliably. So instead, the creators of ARC just gave up and said “Forget it. We're not going to let you put __strong
and __weak
references in structs.”
That's why you can only put an object pointer into a struct if you use __unsafe_unretained
to tell ARC “Don't try to manage ownership of the object that this references.”
You can try to use a struct containing __unsafe_unretained
object references, perhaps using CFRetain
and CFRelease
to manually retain and release them. Then you can create an array of such structs. This is error-prone, so you should only do it if the profiler tells you that it's critical for performance.
Instead, just create a new Objective-C class instead of a struct. Give the class an @property
for each field you would have put in the struct. The use an NSMutableArray
to manage an array of instances of this new class.