In my app at a certain point I'm releasing on of the objects I created using:
[myObject release];
I have a feeling something is not really working over there (I have a bug which I cannot catch, and I have an assumption it has something to do with the memory allocation). I'm trying to look it overt in the Debugger and it seems that the object still have the same values after the "release" line was running.
Am I missing anything?
Is the memory still allocated and being dismissed someplace else? If so, where?
When memory is being released, it’s usually not zeroed out. That means that objects appears to keep their status quo even after deallocated – but you can’t use them anymore, since the memory contents could be reused and overwritten by something else at any moment.
One common simple trick is adding a logging statement to dealloc:
- (void) dealloc
{
NSLog(#"Say bye to %#, kids!", self);
[super dealloc];
}
This is so simple that it can’t go wrong. Which is a good thing when you’re debugging and want to be 100 % sure about something.
Another nice tool is zombies. When you set a special environment variable, the machine will guard access to all objects and will scream when you try to access a deallocated one. It’s also quite a dependable tool.
And then there’s retainCount. It’s probably quite close to what you are looking for, but it’s not very dependable, as there are many things going on in the background. You should only use it if you know what you’re doing.
Instead of releasing it try,
myObject=NULL;
NSLog(#"Retain count of myObject is %d", [myObject retainCount]); // Since retainCount returns an integer, we use %d to display it
You will see that its retaincount is 0.
You can also check myObject value
NSLog(#"myObject Value after NULL = %#", myObject);
myObject Value after NULL = (null)
Related
Let's assume that we create an instance of class var foo: Foo? = Foo() on the main thread and we call some time consuming instance method bar of Foo on another thread, after a short time we set foo to nil on main thread. What happens with the execution of bar, in my understanding bar should still continue its execution since invoking instance method implicitly passes self as the first argument, so even those the last explicit ref to foo was broken we still have a ref inside of a method and it should be good. But then I found this stackoverflow post which completely breaks my understanding. So, can somebody confirm/deny the fact that object cannot be deallocated during its method execution
Short answer is that your belief is correct, and you're looking at a question that's not relevant to Swift.
Your link is to non-ARC Objective-C. Swift always uses ARC, and ARC is very conservative about retains. Consider the following Objective-C call:
[target runMethod: parameter];
Under ARC, this is (conceptually) transformed into:
[target retain];
[parameter retain];
[target runMethod: parameter];
[parameter release];
[target release];
retain and release are atomic, thread-safe calls.
A similar behavior exists in Swift. Because of this, as a general rule (in the absence of Unsafe), a variable cannot "disappear" while you'll holding onto it.
This is the implementation detail. The better way to think about it is that by default variables and parameters are strong, and an object cannot be destroyed while there is a strong reference. This matches your understanding.
Prior to ARC, though, you needed to insert extra retains and releases yourself to protect against this kind of situation, and it was very common not to. (Prior to 10.6, most ObjC was single-threaded.)
Even without threads, there are ways this can go astray without ARC. Since callers often didn't immediately retain returned values if they only needed them temporarily, it was possible to get dangling pointers even without multiple threads. For example, with a trivial accessor with no memory management, this can crash:
NSString *name = [person name];
[person release];
[self doSomethingWithName: name];
This is why you often see old ObjC getters written in the form:
- (NSString*) title {
return [[title retain] autorelease];
}
This made sure that the returned value would survive until the end of the event loop even if self released it or self was deallocated.
Swift does similar things via ARC, but as the name suggests, it's all automatic.
As we all know, object will not dealloc immediately in ARC when no variable refer it. eg,
NSObject* obj = [[NSObject alloc] init];
obj = nil;
obj will dealloc after a time.(auto release pool drain).
Now, I want the obj dealloc right after it's been set to nil, which means the obj is not in auto-release-pool. But all other obj should work well as before, which means the program is still in ARC mode.
Is there a way, maybe macro or compiler flag, to do this?
First of all: You should not care about early deallocation. This is a strong code smell.
Second: Are you really, really sure, because -init does not put an object into ARP. Maybe the expression causes a retain autorelease combination, but compiling in release mode should optimize that away.
However, if it is in ARP you can close the ARP as mentioned by Hermann Klecker or – I think this is better – find the reason for being that object in ARP. There is no need for that.
Amin is right: the object is not in an autorelease pool. alloc, which created the object, does not engage a pool. On the other hand, you're right: ARC may not release the object immediately.
There is indeed an annotation you can use to force the release: objc_precise_lifetime. Adding that to the variable declaration will cause ARC to send release as soon as the object is no longer valid in the current scope.
However, Amin is also right that this is not very likely to be what you want. ARC knows what it's doing -- there are optimizations it can't make when you use this annotation -- and unless you know what it's doing too, you should strongly consider just letting it do its job.
Im constantly being given an error that reads *** -[NSKeyValueObservance retain]: message sent to deallocated instance 0x86c75f10. I have tried running the Zombies template and here is the screenshot of what it provides.
It points to a managedObject, and I'm having trouble figuring out where the object is being deallocated. Here is the block of code that the compiler takes me to after each crash.
- (void)setIsFavourite:(BOOL)isFavourite shouldPostToAnalytics:(BOOL)shouldPostToAnalytics;
{
// check whether we need to generate preferences objects just in time
if(!self.preferences && !self.series.preferences /*&& isFavourite*/)
{
if(self.series)
{
[self.series addPreferencesObject];
}
else
{
[self addPreferencesObject];
}
}
//Crash In here
self.preferences.isFavourite = #(isFavourite);
self.series.preferences.isFavourite = #(isFavourite);
EDIT: If you need to see a larger size of the image here is a larger resolution link.
OK, I hit something similar and found a way to debug this kind of issue with NSKeyValueObservance. To debug, do the following:
In Xcode, open the "Breakpoint Navigator".
Add a new symbolic breakpoint with:
-[NSKeyValueObservance _initWithObserver:property:options:context:originalObservable:]
To that breakpoint, add an action and set it to "Debugger Command".
Set the following command: expr (void)NSLog(#"observer <0x%p>: %# <%p>, property: %#", $arg1, (id)NSStringFromClass((id)[(id)$arg3 class]), $arg3, (id)$arg4)
Click the "Automatically continue after evaluating expression".
Now you can run your application and take the steps necessary to reproduce your crash. And yes, you'll want NSZombies enabled. Note: it's going to run slow and you're going to get a ton of debug output, but just be patient. It'll get there eventually.
When you hit the crash when trying to message a deallocated NSKeyValueObservance, you'll be presented with the address of the original object. Highlight the address and hit cmd-e to enter the text in the search buffer. Then hit cmd-g find the next occurrence of the string in the debugger output. You're going to potentially find the address a couple of times, so look for the address that follows the observer <0x?????> output. The output on that line should tell you what object is being observed and for which property.
In my case, when I figured this all out, it turned out that I was observing a synthesized property that depended on an object in array and during a certain operation, the order of the objects in the array changed without doing the correct KVO notifications, and that caused my crash.
Are you using manual reference counting? If so, why? Convert your app to ARC. Manual reference counting is painful at best, and ARC is much better.
I am an experienced iOS and Mac OS developer and can do either, but I far prefer ARC. It's much less fussy and error-prone.
There is a feature built into Xcode that will convert your project to ARC for you. You might have to do some cleanup afterwords, but it's worth it.
If you do that your problem will likely go away.
As to the specifics, your screenshot is far too small to be able to read it. You will need to post a full-sized image if you want somebody to try to figure out what's going on.
However, in broad terms it sounds to me like you have an autorelease bug.
in manual reference counted code, lots of system method return objects that are "autoreleased." That means that when you receive them their retain count is positive (usually 1) so they stick around. However, they have been added to the "autorelease pool," which means that they are going to be released on the next pass through the event loop if nobody retains them first.
When you receive an autoreleased object you should either accept that it will be released once your current method returns, or retain it.
If you are trying to write Core Data code using manual reference counting and don't understand this then you are setting yourself up for failure.
Core Data is pretty complex, and you should have a solid understanding of Cocoa memory management before attempting to write a program that uses it, especially if you're using manual reference counting.
I have asked this before but I think my question was not understood, so here goes again:
We do not handle memory anymore, since ARC does that. We cannot even invoke memory release commands etc.. So what CAN one do programmatically at RUN TIME to address a memory warning issue if the delegate receives the memory warning notification?
I do NOT want to know how to fix my code!!!
Code cannot fix itself at run time.
Assuming I have coded correctly, BUT still receive a memory warning, what can be done ..
ie Can you give an example of what to code into the
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
;
}
method?
Of course you still have control over memory. You're just operating at a higher abstraction level with ARC.
You can use: object = nil to clear a strong reference. When all strong references are cleared, the object is deallocated.
If you are familiar with manual reference counting:
object = nil; << ARC
is like this when doing your own reference counting:
[object release], object = nil;
Maybe too naive, but what I do is log present values of variables so I can track down errors or what may be causing the warning.
I'm currently developing a game for iOS and we have a memory leak. Our project is ARC set up. I was wondering on how to ensure memory deallocation. One of the steps I was thinking of taking was convert code of the form:
-(void)methodMethod{
Object* o = [[Object alloc] init];
// Some logic
}
into:
-(void)methodMethod{
Object* o = [[Object alloc] init];
// Some logic
o = nil; // Explicit nil assignment
}
Is there a difference between the two? What other measures should I take to ensure a dealloc in an ARC setup?
We're using the Sparrow Framework.
Both methods do the same thing. Local objects are set to nil by ARC when they leave scope, so putting in a manual nil does nothing.
If you want to find a leak - you are far better off actually running it through Instruments with the Leaks tool and finding out what is being leaked, which will give you a better idea of what is going on. It's quite handy for finding retain-cycles.
As pointed out by Abizem, both methods lead to the same results, and require careful passes through Instruments. The results are not always easy to interpret.
In ARC, you should never see a leak - in the usual obj-C meaning -. Sometimes, iOS instruments can report a leak, but most if not all, this comes from the runtime, and I tend to regard them as beyond my control. What you can see however, is uncontrolled memory increase, which is typical of memory retention. Keeping strong pointers on objects is the obvious reason, which in my case has always been the consequence of : retain cycles in code blocks, and incorrect data structure cleanup, i.e. objects are created, then filled into arrays, dictionary, page control etc... but the later were not emptied properly during the app lifecycle.
Also image processing functions still use standard malloc/free directives embedded into internals UIGraphics lib, so in that case you explicitly need to free the memory (CGImageRelease, etc...). ARC will not help here.
hope this helps narrow down the problem, which as Abizem pointed out, should start with Instruments.
the following is unnecessary but (at least for me) the discussion in the comments was helpful and that's why I leave it
wrap the method in an #autoreleasepool. that will make it 99% percent sure it is being deallocated
-(void)methodMethod{
#autoreleasepool {
Object* o = [[Object alloc] init];
// Some logic
}
}
Both are the same.
A better solution to test your class:
- (void)testDealloc
{
__weak CLASS *weakReference;
#autoreleasepool {
CLASS *reference = [[CLASS alloc] init]; // or similar instance creator.
weakReference = reference;
// Test your magic here.
[...]
}
// At this point the everything is working fine, the weak reference must be nil.
XCTAssertNil(weakReference);
}
This works creating an instance to the class we want to deallocate inside #autorealase, that will be released (if we are not leaking) as soon as we exit the block. weakReference will hold the reference to the instance without retaining it, that will be set to nil.