NSZombie created with -Os and Automatic Reference Counting in iOS 5 development - ios

I spent the day working on a strange error in my iOS 5 iPad application, and I was wondering if anyone had some information.
Here's the general setup: There's a UIViewController subclass StoryViewChildController that has two member variables: _currentModel and _comingModel. There is a method in StoryViewChildController that calls [[INEWSStoryModel alloc] init] and returns the resulting object that was created. During viewDidLoad, I have the following code block. Note that this isn't verbatim copied from the code - it's more complicated - but I'm trying to summarize:
_currentModel = [self createModel];
_comingModel = [self createModel];
Then, at some point, I need to be able to swap _currentModel and _comingModel, along with other objects. Here is the swap method, verbatim from my code:
- (void)swapComingPageAndCurrentPage {
[_swapLock lock];
//Swap story views
IPCStoryView *swapPage = _currentPage;
_currentPage = _comingPage;
_comingPage = swapPage;
//Swap models
INEWSStoryModel *swapModel = _currentModel;
_currentModel = _comingModel;
_comingModel = swapModel;
//Swap players
PlayerController *swapPlayer = _currentPlayerController;
_currentPlayerController = _comingPlayerController;
_comingPlayerController = swapPlayer;
// clear out the content of the old view
[_comingPage resetStoryView];
[_comingPlayerController resetPlayer];
_comingPlayerController.view.alpha = 0.0;
_currentPageURI = _lastRequestedStory;
[_swapLock unlock];
}
The problem is: when I'm run my project in Release configuration (which uses -Os for compiler optimization) I crash during the swap of the model objects. The crash comes from attempting to access a Zombie object. I used Instruments to track down the retain/release path of my objects, and coming into this method, _currentModel has a reference count of 1, as expected. However, the line INEWSStoryModel *swapModel = _currentModel; does NOT cause a retain to be called on _currentModel, so the next call _currentModel = _comingModel;, causes the reference count to drop to 0. Then, when swapModel falls out of scope, another release call is attempted, and the program crashes.
It almost seems to me that the compiler optimization is optimizing away retain calls that it should not. Has anyone else had this type of problem? Could I be doing something else wrong? If necessary I can post more code from the class.
Other interesting notes: If I set the swapModel variable as __autoreleasing, the code works. Also, if I add the following code block at the end of the swap method, the code works:
_comingPage.cueView.frame = [_comingPage adjustCueViewFrame:_comingPage.cueView.frame
ForVideoShowing: NO
inOrientation:_currentOrientation];
All that method does is adjust a UIView frame. The fact that I can add unrelated code to the end of the method and have it not create a zombie leads me to think the compiler is optimizing incorrectly. Anyone have any ideas?

Related

CoreData not returning updated values

I'm working with some existing code that interacts with CoreData. I made some changes that I later realized introduced a regression. I was able to isolate the lines of code that introduced the problem, but I cannot for the life of me understand why it's an issue at all.
The code involves reading articles and marking them as read. I didn't make any changes to the marking code and determined that still functions correctly. However, in another layer of the code that's getting the list of read articles, I made the following change:
//Old
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
...
[self retrieveReadArticles];
...
}
- (void)retrieveReadArticles {
userHistory = [UserHistory retrieveUserHistory]; //stored in iVar
self.readArticles = userHistory.readArticles;
}
The above works fine, and gives me an updated list of read articles.
//New
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
...
[self retrieveReadArticles];
...
}
- (void)retrieveReadArticles {
UserHistory* userHistory = [UserHistory retrieveUserHistory]; //local variable
self.readArticles = userHistory.readArticles;
}
This change in scope breaks the functionality, and causes the list of read articles to never update.
A colleague and I were speculating that the ivar allows the operation to complete fully, while the local variable must not be retained properly and goes out of scope before it can return updates. Can anyone point me toward a resource that explains this unexpected behavior?
It looks like the marking code may have been the problem after all. We were retrieving a dictionary of existing read articles, adding another entry to it, and saving the UserHistory object again. Changing that code to create a brand new dictionary with the existing read articles appears to solve the problem without needing to use ivar scope.

Core Data in Unit tests with RZVinyl

Just to give a bit of backdrop: I recently started working on unit tests for the code that had been developed and maintained by some other company. My intention is to write the test cases without touching the application code .
Now coming to the problem: How can one get a reference to the CoreData stack of the application within the unit tests' target. After every service call, the response is stored in the persistent store of CoreData. I want to validate it from the unit tests class. I tried accessing the CoreData stack from unit tests but for some reason it was coming as nil after the code got compiled. Here's the piece of code in my setUp method.
- (void)setUpDataBase
{
RZCoreDataStack *stack = [[RZCoreDataStack alloc] initWithModelName:#"Skillsoft"
configuration:nil
storeType:NSSQLiteStoreType
storeURL:nil
options:RZCoreDataStackOptionDeleteDatabaseIfUnreadable];
NSAssert(stack != nil, #"Failed to create CoreData stack");
stack.mainManagedObjectContext.parentContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy;
[RZCoreDataStack setDefaultStack:stack];
RZCoreDataStack *setStack = [RZCoreDataStack defaultStack];
NSLog(#"setStack Details >>> %#",setStack.description);
}
+ (RZCoreDataStack *)defaultStack
{
if ( s_defaultStack == nil ) {
RZVLogInfo(#"The default stack has been accessed without being configured. Creating a new default stack with the default options.");
// // s_defaultStack = [[RZCoreDataStack alloc] initWithModelName:nil
// configuration:nil
s_defaultStack = [[RZCoreDataStack alloc] initWithModelName:#"Skillsoft"
configuration:nil
storeType:NSSQLiteStoreType
storeURL:nil
options:RZCoreDataStackOptionDeleteDatabaseIfUnreadable];
s_defaultStack.mainManagedObjectContext.parentContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy;
}
return s_defaultStack;
}`
The default stack is a static variable and is coming as nil ... I am assuming that 2 sets of static variables are being created one in application scope and other in unit tests scope ... I just want to write unit test case for a method in UIView controller that, in turn, makes a service call in scope of another layer. I want to validate it by getting a reference to CoreData in app and check if the data is being persisted properly... What is the right way to proceed with that ...
I have seen a couple of StackOverflow posts which suggests to create one's own CoreData stack in the setUp method, but with that I would need to persist the data in the same stack which I don't want to do at this moment ..
I could see that app delegate gets called when your run the unit test cases which in turn initialises quite a few objects in my project ..In order to avoid that , i have made a change in the main file itself to call testing app delegate instead of app's main delegate based on the target .. So all the initializations of the objects are being done in the unit tests..
Please suggest me the right approach to proceed...
P.S For CoreData access, the application uses a third party library named RZVinyl, which kinda made things even more complex for me ..
P.P.S My English is weak, so please let me know if I'm not clear in my explanation. I will update the problem statement..

Block is preventing dealloc although the block was copied

I believe I was following the rules but still a problem exists
My class init includes a block like this:
HTTPChunkReceiveBlock chunkBlock = ^(id connection, NSData *data) {
NSLog(#"Hi there!!");
};
and I am passing this block into an HttpConn obj which my class holds:
operation_ = [[HttpClient sharedClient] performChunkedRequest:url
chunkHandler:chunkBlock];
Now for the problem: my object is never deallocated!!
The problem seems to be caused because the HttpConn is keeping a pointer to the block, but I want to mention two points:
The block is not referring to self!
The HttpConn class is keeping a copy of the block, like this:
chunkBlock_ = [chunkBlock copy];
Any explanation would be greatly appreciated!
EDIT
Extra info:
I have verified that if I'm freeing operation_ then my object is deallocated fine:
reader.operation_ = nil;
reader = nil; //previous line allows 'dealloc' to be called
Now repeating the question: operation did not get a pointer of reader's self, it only holds a copy of the block which do not refer to self!
Ok, I will answer my own question so that others do not fall into the same problem. #DarkDust was actually correct. there was a tiny line which I was completely ignoring:
**retriesNumber++;**
It looks like an innocent sentence, but because retriesNumber is a member of the class, it is actually meaning
(INVISIBLE strong pointer to self)->retriesNumber
so the solution was to declare it as a property (versus a member ivar) so that we can use self to access it, and then write:
pSelf->retriesNumber++;
Thank you guys for your quick support, and I hope others will learn from it too!

IOS: Release for NSString is not working as expected

I found a strange behavior with NSString. I tried to run the below code and noticed this.
NSString *str = [[NSString alloc] initwithstring : #"hello"];
[str release];
NSLog(#" Print the value : %#", str);
Here, in the third line app should crash because we are accessing an object which is released. But it is printing the value of str. It is not crashing. But with NSArray i observed different behavior.
NSArray *array = [[NSArray alloc] initwithobjects : #"1", #"2", nil];
[array release];
NSLog(#"Print : %#", [array objectatindex : 0]);
NSLog(#"Print : %#", [array objectatindex : 0]);
The code has two NSLog statements used for NSArray. Here after releasing when the first NSLog is executed, it is printing value. But when second NSLog is executed, app crashes. App crash is acceptable because the array accessed was released already. But it should crash when the first NSLog is executed. Not the second one.
Help me with this behaviors. How release works in these cases.
Thanks
Jithen
The first example doesn't crash because string literals are never released. The code is really:
NSString *str = #"hello";
[str release];
People get burned with string literals on memory management and mistakenly using == to compare them instead of isEqualToString:. The compiler does some optimizations that lead to misleading results.
Update:
The following code proves my point:
NSString *literal = #"foo";
NSString *second = [NSString stringWithString:literal];
NSString *third = [NSString stringWithString:#"foo"]; // <-- this gives a compiler warning for being redundant
NSLog(#"literal = %p", literal);
NSLog(#"second = %p", second);
NSLog(#"third = %p", third);
This code gives the following output:
2013-02-28 22:03:35.663 SelCast[85617:11303] literal = 0x359c
2013-02-28 22:03:35.666 SelCast[85617:11303] second = 0x359c
2013-02-28 22:03:35.668 SelCast[85617:11303] third = 0x359c
Notice that all three variable point to the same memory.
Your second example crashes at the second NSLog because at the first log, the memory where array was hasn't been re-used, but that first log causes enough activity on the heap to cause the memory to become used by something else. Then, when you try to access it again, you get a crash.
Whenever an object is deallocated and its memory marked as free, there is going to be some period of time where that memory still stores what's left of that object. During this time you can still call methods on such objects and so forth, without crashing. This time is extremely short, and if you're running a lot of threads it may not even be enough to get your method call in. So clearly, don't rely on this implementation detail for any behavior.
As others have said, regarding your first question, NSString literals aren't going to be deallocated. This is true for some other Foundation classes (NSNumber comes to mind) but is an implementation detail as well. If you need to do experiments on memory management, use an NSObject instance instead, as it will not show the unusual behaviors.
When you send a release message on an object, the object is actually not being removed from the memory. The release message simply decrements the reference count by one only. If the reference count is zero the object is marked as free. Then the system remove it from the memory. Until this deallocation happens you can access your object. Even if you release the object your object pointer still points to the object unless you are assigning nil to the pointer.
The first example doesn't crash because string literals are never released. Where the second totally depends on release and retain counter.
Read this article. Its contains short-and-sweet explanation for your query
You Should read this apple guideline
You seem to assume that release should destroy the object immediately. I don't think that's the guarantee that the language makes. What release means is: I have finished using this object and I promise not to use it again. From that point onwards it's up to the system to decide when to actually deallocate the memory.
Any behaviour you see beyond that is not defined and may change from one version of the Objective C runtime to the next.
That's to say that the other answers that suggest the difference is string literals and re-use of memory are currently correct but assuming that the behaviour will always be like this would likely be a mistake.

why not EXC_BAD_ACCESS?

I've written the following code:
NSString *string = [[NSString alloc] initWithFormat:#"test"];
[string release];
NSLog(#"string lenght = %d", [string length]);
//Why I don't get EXC_BAD_ACCESS at this point?
I should, it should be released. The retainCount should be 0 after last release, so why is it not?
P.S.
I am using latest XCode.
Update:
NSString *string = [[NSString alloc] initWithFormat:#"test"];
NSLog(#"retainCount before = %d", [string retainCount]);// => 1
[string release];
NSLog(#"retainCount after = %d", [string retainCount]);// => 1 Why!?
In this case, the frameworks are likely returning the literal #"test" from NSString *string = [[NSString alloc] initWithFormat:#"test"];. That is, it determines the literal may be reused, and reuses it in this context. After all, the input matches the output.
However, you should not rely on these internal optimizations in your programs -- just stick with the reference counting rules and well-defined behavior.
Update
David's comment caused me to look into this. On the system I tested, NSString *string = [[NSString alloc] initWithFormat:#"test"]; returns a new object. Your program messages an object which should have been released, and is not eligible for the immortal string status.
Your program still falls into undefined territory, and happens to appear to give the correct results in some cases only as an artifact of implementation details -- or just purely coincidence. As David pointed out, adding 'stuff' between the release and the log can cause string to really be destroyed and potentially reused. If you really want to know why this all works, you could read the objc runtime sources or crawl through the runtime's assembly as it executes. Some of it may have an explanation (runtime implementation details), and some of it is purely coincidence.
Doing things to a released object is an undefined behavior. Meaning - sometimes you get away with it, sometimes it crashes, sometimes it crashes a minute later in a completely different spot, sometimes a variable ten files away gets mysteriously modified.
To catch those issues, use the NSZombie technique. Look it up. That, and some coding discipline.
This time, you got away because the freed up memory hasn't been overwritten by anything yet. The memory that string points at still contains the bytes of a string object with the right length. Some time later, something else will be there, or the memory address won't be valid anymore. And there's no telling when this happens.
Sending messages to nil objects is, however, legitimate. That's a defined behavior in Objective C, in fact - nothing happens, 0 or nil is returned.
Update:
Ok. I'm tired and didn't read your question carefully enough.
The reason you are not crashing is pure luck. At first I though that you were using initWithString: in which case all the answers (including my original one (below)) about string literals would be valid.
What I mean by "pure luck"
The reason this works is just that the object is released but your pointer still points to where it used to be and the memory is not overwritten before you read it again. So when you access the variable you read from the untouched memory which means that you get a valid object back. Doing the above is VERY dangerous and will eventually cause a crash in the future!
If you start creating more object in between the release and the log then there is a chance that one of them will use the same memory as your string had and then you would crash when trying to read the old memory.
It is even so fragile that calling log twice in a row will cause a crash.
Original answer:
String literals never get released!
Take a look at my answer for this question for a description of why this is.
This answer also has a good explanation.
One possible explanation: You're superfluously dynamically allocating a string instead of just using the constant. Probably Cocoa already knows that's just a waste of memory (if you're not creating a mutable string), so it maybe releases the allocated object and returns the constant string instead. And on a constant string, release and retain have no effect.
To prove this, it's worth comparing the returned pointer to the constant string itself:
int main()
{
NSString *s = #"Hello World!";
NSString *t = [[NSString alloc] initWithFormat:s];
if (s == t)
NSLog(#"Strings are the same");
else
NSLog(#"Not the same; another instance was allocated");
return 0;
}

Resources