In my application, I create many instances of NSColorwell, and as I create each new instance, I assign it to an array of NSColorwells. By assigning the instances to an array, I maintain a reference to each of them so that I am able to manipulate the position and color of the NSColorwells. So far, so good. But when I no longer need the NSColorwells, I cannot delete them. What I really want to do is free up the memory that they have been using. I tried the removeAll() method for the array, but that merely cleared the array. No real surprise.
Is there a way to reclaim the memory?
I used removeFromSuperview(), which appears to free up the memory.
while (index < CW.count) {
CW[index].removeFromSuperview()
index += 1
}
CW.removeAll()
Related
I need to create a cache, that could save some objects, but then, at some point when I have memory warning or simply user wants it, I would like to purge all instances that are used only in the cache at the moment.
In other words: I need to deinit objects with ARC count == 1. The problem is that based on my googling of this project, it is not possible in pure Swift to get the retain count of an object.
From my experience I see that it is not possible by default in Swift. In objective-c I was using Proxy object, that was returned from cache, it had such overriden methods:
// Forward class checks for assertions.
-(BOOL)isKindOfClass:(Class)aClass {return [_target isKindOfClass:aClass];}
- (id)forwardingTargetForSelector:(SEL)aSelector
{
return(_target);
}
But is of course not applicable to Swift ideology.
One thought that I have is to base my cache on array of WeakBoxes, but this way unused objects will be deallocated when they become unused and that doesnt meet my requirements.
Can somebody guide me to some Swift possibilities, that I'm not aware of, to achieve such thing?
You do not need to mess with the retain count of the object. Your cache can just hold a strong reference. This guarantees that the retain count is always at least one. When you get a memory warning you just loop through every pointer in the cache and set it to nil. Assuming no one else has a strong reference this decrements the reference count to zero and the object immediately calls deinit and goes out of memory. If you really really want the object to go out of memory when the cache does a purge, make sure only the cache has a strong reference to the items being held and that everyone else takes a weak reference. I have a lazily loaded array of ViewControllers that does something similar:
fileprivate var controllers = [UIViewController?](repeating: nil, count: DashboardInfo.Category.allValues.count)
override func didReceiveMemoryWarning() {
//Release every off screen controller
for index in 0 ..< controllers.count {
if controllers[index] != currentController {
controllers[index]?.removeFromParentViewController()
controllers[index]?.view.removeFromSuperview()
controllers[index] = nil
}
}
}
We have address book feature in our application, contacts are stored in NSMutableArray. I
have a separate class which is accessing contacts from outside, so I have initialized like
below in new class...
self.newListdata = [address_book_window listData];
Now my new class is able to access all contact using newListdata, number of contacts also
matching. In one situation if any contacts deleted from address book at run time, new
class newListdata also need to be updated, but it is not updating as I thought. Count is
also not updating. Am I doing anything wrong, Do I need to manually delete the contact in
newListdata also. Why it is not synchronized with address book contact as I am pointing to
address book list data.I have been learning objective C, so if anyone can help it will be
useful. thanks.
compare if newListdata and [address_book_window listData] are the same pointer (the same object).
printf("compare %f and %f", newlistdata, [address_book_window listData])
They should be the same address storage.
Note: since i don't know how you have implemented your code, since listData is encapsulated, address_book_window doesn't guaranty listData will always be at the same address storage (if you use a new list data by example). So newListData will could potentially point to a dangling pointer.
Best way to keep track of an object like this is by observer pattern, or KVO if you can. Since they are long to explain, google it ;)
if you have 2 NSMutableArrays they have strong references to the same objects, but they are 2 unique objects (they are 2 MutableArrays), this is the case when for example you create a NSMutableArray arrayWithArray:
if you have 1 Array, and 2 references to it when you remove or add object to it, it's a single object so it does not matter which reference you use to access it, it will be in "sync" as you mention (saying in sync is not correct because in fact they are 1 single object)
In your case maybe listData return a new array that contains references to the same objects, in such a case when you remove an object from one array, the second will still retain it (the object will not be deallocated then) and the 2 arrays will be different.
I have a mutable array that contains the sounds that are being played.
I have a continous process that parse that array to adjust volumes and some other things.
Sometimes, a new sound is played and must be added to that array just before it's play starts.
And sometimes, I have a crash because my array "was mutated while being enumerated".
How may I solve that ?
You can't easily change an array while it's enumerating.
Enumerate through the array and note the new sound to be added (using a variable, or a separate array if you need to note more than one). When the enumeration is finished, add the sound to the array.
Alternatively, make a copy of the array, enumerate the copy and add the sound to the original one when you need to.
It would be nice to see any code here. But according what you are saying, i think the problem lies in the way that you use to iterate through the array. I guess it looks like this:
for ( type *object in myArray) {
...
}
Now, as you exception tells you, you can't modify the array while doing this. If you, on the other hand, access the array's values via the indexes, it should work:
for (int i = 0; i < myArray.count; i++) {
[myArray objectAtIndex:i]...
}
Keep in mind however, that the indexes aren't 'stable' that way, especially if you remove objects.
1) What is the reason for the use of retain?
For example, in a setter method:
- (void) setCount: (int) input {
[intCount autorelease];
intCount = [input retain];
}
2) the autorelease-Method: Is it deleting an old object or preparing the new one?
3) Why the retain-method is called at the input-object?
Would
intCount = input;
be wrong?
And why?
Retain is used to increment the retainCount of an object. NSObjects have a property called retainCount which maintains a count on the number of references that are currently held on an object. When the retainCount of an object reaches 0, the object can be released from memory. Effectively this prevents an object from being released from memory if it's still in use elsewhere.
The autorelease method does not delete an old object and does not prepare the new object. It is effectively a pre-emptive call to release the object (autorelease is much more complicated than that and you should read up on it in the Memory Management Guide.)
In your case intCount = input wouldn't be wrong because you're working with a primative. However if input were an object then you'd need to be calling retain on it. In fact you don't even need to be writing your own getters/setters for primatives (or objects), but instead should be using Declared Properties. In fact you're almost always better off using Declared Properties and if you do want to roll your own, get to know the pitfalls of doing so first.
I recommend you read this. http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
The answers to your questions have been answered fairly well so let me just add that if you can use garbage collection you should. It makes everything so much easier. It isn't a panacea and you still should learn to use the retain/release mechanism but unless you are dealing in some high volume memory calls, creating and deleting lots of objects, then just use garbage collection.
It can be found under Project | Edit Project Settings | Build
Then just search for "garbage" and you'll see it.
If you are doing iOS development and cannot use garbage collection I apologize for giving unhelpful information but it still stands for non-iOS development.
To answer ur question specifically:
1). the use of retain is to declare the ownership of an object. In this case, intCount retains the ownership of input, in case the input got released somewhere else, u can still use the intCount.
2). the autorelease of intCount is to relinquish the ownership of the old value. That avoid the memory leak of the old value. If u don't release the old value, and u assign a new value to this pointer, the old object will always be there and never got released, which will cause the memory leak.
3). if u don't retain the input, and the parameter of input got released somewhere else. then if nowhere else retain this object, it will get freed. So u can't use intCount as well. That's why u need to retain it or copy it.
But i think if u do intCount = input; it should be fine. Because int is not an object, it's just a type. So I think the whole method is okay to be written like this:
- (void) setCount: (int) input {
intCount = input;
}
But if its a pointer, u should not assign the new value to the old one directly.
I have an iPhone app which deals with a subset of 25,000 places at any given time.
I'd like to maintain a cache of places so that I know that if one part of my application updates a place, every other part that knows about that place sees the update.
My naive implementation is create an NSMutableSet to store references to the cached places.
Methods that find new places will first check the cache and return the cached object or if the place isn't in the cache, they will create a new place object and add it to the cache.
The problem is how do I release objects that are no longer needed?
The NSMutableSet will retain the place so the retainCount will never go to zero and dealloc will never be called.
Is there a kosher method to handle the release scenario? Is there some other pattern for doing this that I'm not aware of.
(and CoreData is not an option at this point, but I understand that it handles this).
Thank you,
On the desktop you can do this with NSPointerSet, on the iPhone it is a bit more difficult.
You can use CoreFoundation to create a non-retaining set if you really want to:
//Default callbacks
CFSetCallBacks callbacks = kCFTypeSetCallBacks;
//Disable retain and release
callbacks.retain = NULL;
callbacks.release = NULL;
cachedPlaces = (NSMutableSet *)CFSetCreateMutable(kCFAllocatorDefault,
0,
&callbacks);
That makes a non-retaining set. Note that you still need to remove the objects from the set when they are released, otherwise you will have stale pointers in your set that will cause you to crash on a deref. So in the objects you are adding to the set you need a dealloc something like this:
- (void)dealloc {
[cachedPlaces removeObject:self];
[super dealloc];
}
This is only really suitable for a purely in memory cache of extant references, if you need to also move stuff to and from the disk then CoreData basically takes care of all of this for you.
You could use NSMutableSet as cache and rely on the fact that any object it contains with a retain count of 1 is only owned by the cache. Thus any object with a retain count of 1 should be removed, this is easily done:
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"retainCount > 1"];
[cachedPlaces filterUsingPredicate:predicate];
Do this on a timer, or whenever a a place is added and/or removed if that is not too often. You could also make the predicate a static to avoid generating anew instance every time.
Use Core Data if you can deploy to iPhoneOS 3.0 or greater, or use SQLite for iPhoneOS 2.x. Either way you'll be able to use a database to store your data, and you'll be able to do queries to get fresh data sets.
As of iOS 4.0, the proper way to do this is to use an NSCache. It can automatically purge objects when the system sends a low-memory warning. You can also set limits on the cache size.
NSCache Class Reference
This question is old, but I recently came across a similar issue. I believe using NSHashTable can fit the requirements of this situation.
NSHashTable works better than NSCache or NSSet because it can hold weak references to your instances, so that once all references are dropped the instance is automatically removed from the NSHashTable thanks to ARC. This works as a kind of 'Just-in-Time' caching method, only retaining objects held elsewhere by strong references.
Considering that you have multiple parts of the application that could be adding references, using the NSHashTable as the Flyweight Pool of the Flyweight Pattern could be useful. The second part of the Flyweight pattern requires a factory, the factory would be responsible for checking for the instance in the pool, adding it to the pool if it's not found, then returning the pooled instance.