retain C array in objective-c - objective-c

i create a c array in the firstClass (this is created in the interface):
BOOL taken[25];
i then go to a different view and come back to the first one, except my c array is reset to 0,
how do i retain my array when i go back an forth between views?

You cannot send retain messages to plain C arrays. Normal C memory management applies. I.e. local stack variables will fade away when out of scope, global variables will live, etc. Use dynamically allocated memory (malloc or new in C++) if you need "long-living" memory, but you are responsible to free it when you're done with it.

The lifetime of an immediate array like "BOOL taken[25]" is the same as the lifetime of the object that it is in. If the surrounding object gets deallocated the array goes with it; conversely, if the surrounding object is retained then so is the array. So to keep this array around, make sure the view is not deallocated, and make sure it's the same view object as you used last time.
In terms of iOS view control in particular (which is I think what you're asking about), try to write your business logic in your "view controller", and have it re-use UIView objects. Or, if you don't re-use the same view, at least have it initialize the new view (including the array) to the correct value.

Related

Removing views, ARC, differences from Objective C and Swift

In Objective C, if a ViewController has a UIKit object property, lets just say a view, and is instantiated in viewDidLoad, followed by being added to the subview, in order to remove it out of memory, both removeFromSuperview() and setting the object to nil must be done (if I'm not mistaken, but I could be...)
However, in Swift, only things with the optional type can hold a value of nil.
My question is, if I would like to animate things like UILabels or UIViews within my application, and later have them disappear (to both the user and removed from memory), would having that UIKit object being removeFromSuperView() be enough? or would I have to make all objects that I'm trying to animate optional, removeFromSuperView() and then set them to nil?
I apologize for my poor articulation. If further clarification is needed, please let me know. Much thanks for your input.
If you want the weak property objects to deallocate, then yes, you have to set them to nil or wait for the owning object to deallocate.
Objects in properties that are not weak will get a release call when the parent object is deallocated. This means the objects will also get deallocated if nothing else is keeping a reference to them.
If you create a temporary UILabel that's not a property of the View Controller and animate it and then removeFromSuperview() it, then it should disappear from memory as well.
As it was retained (refcount: 1) when the function creating the animation was running, later by the view hierarchy (refcount: 2), the function ended (refcount: 1), so only the view hierarchy was retaining it. If you removed it at the end of animation (refcount: 0) it is deallocated.

Remove Object From SuperView but Memory still allocated? (ARC)

I'm having some issues with my application's memory management. I allocate an NSView class and put it on one of my Windows. After some time, I remove the object from the superview and then put another object in it's place. The problem that I'm having is that the memory isn't freed when I remove it. It continues to hold as much memory as it previously held, and if I add more of that class, it continues to pile onto the memory. My question is, will removing that object get rid of all objects that the class held, or are some pointers being held onto, even after the object is removed? I can post code if necessary.
Thanks!
Edit:
Here's the code that I use to allocate it
MyClass *theClass1 = [[MyClass alloc] initWithFrame:frameRect];
[self.window.contentView addSubview:theClass1];
Here's the code that I use to deallocate it
[[self.window.contentView subviews] makeObjectsPerformSelector:#selector(removeFromSuperview)];
I create it on a timer, updated every minute. I do not reference it anywhere else.
The memory for each object should be treated separately for each instance of a class. Removing one instance should not affect the allocation of other instances (unless you had some custom code looking for other instances of the class).
As for the NSView removal, removeFromSuperview does release the receiver (the view being removed), which is why the Apple docs on NSView say to retain it if it is still needed later.
Posting the code where it is declared, instantiated, added, then removed would be helpful for a more specific answer.

what is the best way to deal with removing objects in multiple arrays?

I've got a class that generates a bunch of objects of random types and stores them (well-- references to them) in an array. As it's doing this, it also stores references to them in an array specific to their type.
Later, each array that is type-specific is iterated over and the objects in them have their x position decremented. Within that loop, if they are on the screen, they are added to yet another array of visible objects. Once they go off the screen they are removed from that visible object array.
The rule of my game is: an object can only be destroyed when it's visible. so when an attempt to destroy an object is made, it searches the visible object array and attempts to locate the object, if it's found then it is removed.
The problem is, once the object has been removed from the "visible array", the "type-specific" array continues to be looped over and all those objects get their x position decremented-- even though an object might no longer on the screen.
I am wondering what the best way to remove all references to the object is? I was hesitant to go through all the arrays and call "removeObjectIdenticalTo" on them... My initial solution was to just add a BOOL property to my object "destroyed", and set that to YES if it's been destroyed while on screen, and then have my x decrementing looop skip objects that have been destroyed.... But I started wondering if that's not the best approach as far as memory management goes since that object is sticking around longer than it needs to......
How should one deal with this?
I was hesitant to go through all the arrays and call "removeObjectIdenticalTo" on them
Why? Is it because you imagine this is inefficient? How do you know?
However, for true efficiency, and assuming the objects are all different objects, use NSSet, not NSArray. Access to a particular object is guaranteed efficient.
This may work if you started by storing all of the objects in a dictionary. Following that, add a property to the objects (that are being passed around) that contains a NSString identical to the dictionary key for the array that it lives in.
Then all you would have to do is:
NSMutable *array = [dicionary objectForKey:object.dictionaryKeyString];
//then remove the object from *array

Adding array from one view to another and retaining values

I have four views, with four arrays. As soon as I navigate from one view, I add that particular array to my master array.
Initially this master array has nothing, and is allocated when the app runs using 'init' method. It does not have a view and it is an array from a subclass of NSObject.
Finally the master array should consist of {viewarray1, viewarray2, viewarray3, viewarray4}.
Each array is added to the master array when navigating to the next view.
So is there anything wrong in my implementation ? Is it okay to allocate masterArray in the init method? Each time I add an object to masterArray, I NSLog it and it displays (null)
How can I have the master array retain values for the whole app??
Some Information on the Code:
I initialize my master array in another class, in the -(init) method
masterArray = [[NSMutableArray alloc] init ];
While adding an object to MasterArray from another view, I reference that class, and I create an object for the class, and add it as a property and synthesize it. I then use
[self.thatClassObject.masterArray addObject:self.viewArray1];
There are two ways you could go about initializing it that I can think of offhand. First, you could alloc/init the array in the app delegate. This will ensure it's created before the rest of the views get a chance to add to it.
EDIT: There's only really one way I can think to do this as Josh Caswell pointed out a good fact that class initializations won't work for this situation. You're best off calling alloc/init for the array either in the app delegate or whichever view is made key window first. You'll have to reference it to the other classes from there

How to add alive object to NSMutableArray and remove them when they're released?

I have class Item and class List (which has an NSMutableArray).
Every time class Item is instantiated (and destroyed) it posts a notification, which is listened-to by class List. When class List receives the notification is adds the instance of class Item to its list.
I'm trying to have class Item also post a notification that its about to be dealloc'd. The problem is that class List's NSMutableArray retains the instance of class Item.
What's the most appropriate means of handling this situation? If I decrement the count when adding it to List's array, then an exception will be thrown when class List attempts to call removeObject (since it'll try to dealloc the object.)
Basically, I want a "monitor" class List that contains a list of all "live" instances of Item. But, I also need the ability to release/dealloc the instances and have them report they're being dealloc'd so List can remove them from its NSMutableArray.
Thanks for your help.
If I understand correctly, you want an array that maintains weak references to its items, as opposed to strong references?
I don't know of a way to do this with anything "built-in" in Cocoa. The only way I'd know of to do this is to make the array yourself, and have the storage be __weak id[]. That would automatically zero-out the place in the array when the object deallocates. If you're under the retain-release model, you could use something like MAZeroingWeakRef to get the same behavior.
This is definitely an interesting question, and I don't know of an easier answer. I'd love to be proven wrong!
Ha, I love being wrong!
There's a class called NSPointerArray that looks like it can do what you're looking for. However, it's only available on the Mac, and it only auto-zeros when you're using garbage collection.
I'll keep thinking about this. This is an interesting problem! :)
So I kept thinking about this, and came up with a solution. It uses two unconventional things:
A subclass of NSMutableArray (egads!)
Using an associated object to determine object deallocation
For the first bit, I had to to subclass NSMutableArray so that I could inject some custom logic into addObject: (and related methods). I didn't want to do this via swizzling, since NSArray and friends are a class cluster, and swizzling into/out of clusters is fraught with peril. So, a subclass. This is fine, but we're going to lose some of the awesome features we get from "pure" NSArray instances, like how they do weird things when they get big. Oh well, such is life.
As for the second bit, I needed a way for any arbitrary object to notify that it is about to or just finished deallocating. I thought of dynamically subclassing the object's class, injecting my own dealloc/finalize method, calling super, and then smashing the isa of the object, but that just seemed a little too crazy.
So, I decided to take advantage of a fun little thing called associated objects. These are to ivars what categories are to classes: they allow you to dynamically add and remove pseudo-instance variables at runtime. They also have the awesome side effect of getting automatically cleaned up with the object deallocates. So what I did is just created a little throw away object that posts a notification when it is deallocated, and then attached it to the regular object. That way when the regular object is deallocated, the throw away object will be as well, resulting in a notification being posted, which I then listen for in the NSMutableArray subclass. The notification contains a (stale) pointer to the object that is in the process of getting destroyed, but since I only care about the pointer and not the object, that's OK.
The upshot of all of this is that you can do:
DDAutozeroingArray *array = [DDAutozeroingArray array];
NSObject *o = [[NSObject alloc] init];
[array addObject:o];
NSLog(#"%ld", [array count]); //logs "1"
[o release];
NSLog(#"%ld", [array count]); //logs "0"
The source is on github, and it should (theoretically) work just as well on iOS as Mac OS X (regardless of GC mode): https://github.com/davedelong/Demos
Cheers!
... and I just thought of a way to do this without a custom subclass, but I'm tired and will post the updated answer tomorrow.
the next morning...
I've just updated the project on Github with an NSMutableArray category that allows you to create a true NSMutableArray that auto-zeroes its objects as they're deallocated. The trick was to create a CFMutableArrayRef with a custom retain callback that sets up the proper observation, and then just cast that CFMutableArrayRef to an NSMutableArray and use that (ah, the magic of Toll-Free Bridging).
This means you can now do:
NSMutableArray *array = [NSMutableArray autozeroingArray];
I added a typedef to define these as NSAutozeroingMutableArray, just to make it explicitly clear that while this is an NSMutableArray, it doesn't retain its objects like a normal NSMutableArray. However, since it's just a typedef and not a subclass, you can use them interchangeably.
I haven’t tested this, so comments are welcome.
You could use an NSPointerArray for the list (in a retain property):
self.array = [NSPointerArray pointerArrayWithWeakObjects];
When an Item object is created, it would post a notification that’s listened by your List class. Upon receiving the notification, List adds the object to the pointer array:
[array addPointer:pointerToTheObject];
In this setting, the pointer array doesn’t keep a strong reference to its elements — in particular, it doesn’t retain them. This applies to both garbage-collected and non-garbage-collected builds.
In a garbage-collected build, if an element is garbage collected then the garbage collector automatically assigns NULL to the position in the array where the object was stored.
In a non-garbage-collected build, you’ll need to manually remove the element or assign NULL to the position in the array where it was stored. You can do this by overriding -[Item dealloc] and posting a notification that the object is being deallocated. Your List class, upon receiving the notification, would act upon it.
Note that, since objects are not owned by the pointer array, you must keep a strong reference to (or retain) them if you want to keep them alive.