Weird !=nil check issue - objective-c

I have a UITableViewController which has a UIView* called errorView that is used to overlay an error message over the table view if a method fails to load web data.
In the init method, errorView is set to nil (0x0 in debugger).
In a load method, called at the end of init AND if a 'refresh' UIButton (on the errorView) is tapped, errorView is compared to nil, and removed from superview and released if it is not nil (Still shows 0x0 in debugger).
In the dealloc method, the same check is done before releasing; but for some reason the variable is never nil even though it hasn't been assigned (0xc000 in debugger) because the data failed method was never called. The app then crashes because it tries to dealloc a null pointer that is != nil.
Example:
-(id)init {
errorView = nil;
[self Load];
}
-(void)Load {
if(errorView != nil) {
[errorView removeFromSuperView];
[errorView release];
errorView = nil;
}
//Attempt to load data from web
}
-(void)dataFailedToLoad (e.g. UIWebView didFailLoadWithError) {
errorView = [[UIView alloc] initWithFrame, etc];
[self.tableView addSubview:errorView];
}
-(void)dealloc {
if(errorView != nil)
[errorView release]; //Always crashes because errorView is never nil even though it has been assigned nil?
}
I'm pulling hair out over this. The errorView variable IS NOT USED anywhere else but in these methods as described, and everything I can read into suggests it is the proper way to do it.

As a point of interest; sending a message to a nil object is not an error; a significant number of your checks are completely useless.
Exactly what is going on here is hard to point out without more information; if dataFailedToLoad actually is the only place where errorView is assigned, your code should work. However, it's failure indicates that something else is screwing your pooch.
Incidentally, a null pointer that != nil isn't a null pointer.

Just because you called init the view doesn't have to be initialized. You should use the standard method viewDidLoad to ensure that the view isn't nil.

Are you sure you are talking to the instance you think you are talking to?
I've seen quite a few SO questions that have boiled down to confusion between what the loading of an interface file (xib) instantiates and what the developer needs to instantiate.
I.e. do something like NSLog(#"%# %p", self, self); in all the methods and make sure the address-- the instance-- is the same.

Related

BAD_ACCESS crash unless I create a string with # - Using ARC [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
If I pass testString2 to the next view controller (where the string is assigned to a property of a NSManagedObject subclass), the app crashes soon after with a BAD_ACCESS error. I was able to determine the string was turning into a zombie a while after attaching it to the managed object and also assigning it to a class member of the receiving view controller, to try and eliminate this problem. However, it doesn't turn into a zombie until well after it has been assigned as described.
IF, however, I send testString instead of testString2 to the next view controller, no crashes and everything is happy. Incidentally, newKw is text from a text field, but using strings retrieved from a dictionary gives the same result. I have also tried using [NSString stringWithString:newKw] and other NSString methods in an attempt to create a brand new string, and I get the same result then too.
If I send nil instead of sending any string, there are no errors.
The managed object is never lost or corrupted if I pass testString. But if I pass testString2, it appears when the variable turns into a zombie, it takes out the managed object too because everything in the description is gone and is not shown as a fault. Following some other advice I have seen, I set a breakpoint for malloc_error_break, and in my log I see this:
Power Passage(3734,0x2dae1a8) malloc: *** error for object 0x9aa67b0: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Here is where it is passed from the VC where the string originated:
if (proceed) {
NSString *testString = #"testing123";
NSString *testString2 = newKw;
[self.navigationController pushViewController:[[NewKeywordSummary alloc] initWithKeyword:testString2] animated:YES];
Here is the property where the pointer is getting stored in the managed object:
#property (nonatomic, retain) NSString * newKeyword;
Here is the method newKw is being sent to:
-(instancetype)initWithKeyword:(NSString *)kw
{
if (self = [self init]) {
//Create a new request
kwReq = [ppKeywordRequest keywordRequestInContext:editingContext];
newKw = kw;
kwReq.newKeyword = newKw;
}
return self;
}
Then the kwReq object is passed to the next VC:
-(void)viewBtnHandler:(UIButton *)btn
{
if (btn == addNewTagBtn) {
[self.navigationController pushViewController:[[TagSummaryVC alloc] initWithKeywordRequest:kwReq tagSubmission:nil] animated:YES];
}
}
and it goes here:
-(instancetype)initWithKeywordRequest:(ppKeywordRequest *)req tagSubmission:(ppTagSubmission *)t
{
if (self = [super init]) {
delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
user = delegate.user;
phrases = [delegate.languagePhrases objectForKey:#"TagSummaryVC"];
if (req) {
editingContext = req.managedObjectContext;
kwReq = req;
}
else {
editingContext = [[NSManagedObjectContext alloc] init];
[editingContext setPersistentStoreCoordinator:[delegate.localDataContext persistentStoreCoordinator]];
delegate.editingContext = editingContext;
}
if (!t) {
ts = [ppTagSubmission tagSubmissionInContext:editingContext];
newTS = YES;
}
else
ts = (id)[editingContext objectWithID:[t objectID]];
self.navigationItem.backBarButtonItem =
[[UIBarButtonItem alloc] initWithTitle:#""
style:UIBarButtonItemStyleBordered
target:nil
action:nil];
}
return self;
}
And it returns to NewKeywordSummary here:
if (alertView.tag == AttachAlert) {
if (index == 0)
return;
NSString *testString = kwReq.newKeyword;
NSLog([NSString stringWithFormat:#"Test variable is %#", kwReq.newKeyword]);
[kwReq addTagSubmissionsObject:ts];
[self.navigationController popViewControllerAnimated:YES];
}
}
My NSLogs before and after it is a zombie:
2014-08-04 21:00:52.306 Power Passage[3838:60b] Test variable is vcxvzcx
2014-08-04 21:00:53.378 Power Passage[3838:60b] Test variable is vcxvzcx
2014-08-04 21:00:55.908 Power Passage[3838:60b] Test variable is <__NSMallocBlock__: 0x8ea4b00>
(lldb)
Make sure your NSString references are assigned to a #property on your classes (plenty of examples of assigning and using properties on iOS) using an appropriate storage type (strong or retain, for example). And, yes you are correct any "standard" string in an iOS app is usually an instance of NSString, and thus required the "#" symbol in front.
Try setting a break point on Exceptions ... this will help you identify the offending statement.
I would suggest picking up a book on an intro to Objective-C / iOS / iPad development ... I think you'll find the information invaluable and a HUGE time saver.
I believe I have found the answer to my question. I ran into this post:
why can't I declare a variable like "newVariable" in Obj-C?
Quote from the link:"Objective-C has a naming convention for memory management that is enforced by the compiler. Methods that start with new (also "alloc", "copy", "mutableCopy") are required to return an object that will be "owned" by the caller. See the documentation." (thanks progrmr!)
and realized that I had a property that started with "new", and while it wasn't being synthesized it WAS generating setters/getters with #dynamic... so every time the member kwReq.newKeyword was referenced on my managed object, I am guessing that the compiler was trying to change ownership or otherwise alter the retain count - so after a couple times I was out of retains. So I changed the member name to reqKw, and I have no more problem. I was NOT getting any kind of warning on this.(thanks Apple:-)

capturing self strongly in this block is likely to lead to a retain cycle

How can I avoid this warning in xcode. Here is the code snippet:
[player(AVPlayer object) addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(0.1, 100)
queue:nil usingBlock:^(CMTime time) {
current+=1;
if(current==60)
{
min+=(current/60);
current = 0;
}
[timerDisp(UILabel) setText:[NSString stringWithFormat:#"%02d:%02d",min,current]];///warning occurs in this line
}];
The capture of self here is coming in with your implicit property access of self.timerDisp - you can't refer to self or properties on self from within a block that will be strongly retained by self.
You can get around this by creating a weak reference to self before accessing timerDisp inside your block:
__weak typeof(self) weakSelf = self;
[player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(0.1, 100)
queue:nil
usingBlock:^(CMTime time) {
current+=1;
if(current==60)
{
min+=(current/60);
current = 0;
}
[weakSelf.timerDisp setText:[NSString stringWithFormat:#"%02d:%02d",min,current]];
}];
__weak MyClass *self_ = self; // that's enough
self.loadingDidFinishHandler = ^(NSArray *receivedItems, NSError *error){
if (!error) {
[self_ showAlertWithError:error];
} else {
self_.items = [NSArray arrayWithArray:receivedItems];
[self_.tableView reloadData];
}
};
And one very important thing to remember:
do not use instance variables directly in block, use it as a properties of weak object, sample:
self.loadingDidFinishHandler = ^(NSArray *receivedItems, NSError *error){
if (!error) {
[self_ showAlertWithError:error];
} else {
self_.items = [NSArray arrayWithArray:receivedItems];
[_tableView reloadData]; // BAD! IT ALSO WILL BRING YOU TO RETAIN LOOP
}
};
and don't forget to do:
- (void)dealloc {
self.loadingCompletionHandler = NULL;
}
another issue can appear if you will pass weak copy of not retained by anybody object:
MyViewController *vcToGo = [[MyViewCOntroller alloc] init];
__weak MyViewController *vcToGo_ = vcToGo;
self.loadingCompletion = ^{
[vcToGo_ doSomePrecessing];
};
if vcToGo will be deallocated and then this block fired I believe you will get crash with unrecognized selector to a trash which is contains vcToGo_ variable now. Try to control it.
Better version
__strong typeof(self) strongSelf = weakSelf;
Create a strong reference to that weak version as the first line in your block. If self still exists when the block starts to execute and hasn’t fallen back to nil, this line ensures it persists throughout the block’s execution lifetime.
So the whole thing would be like this:
// Establish the weak self reference
__weak typeof(self) weakSelf = self;
[player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(0.1, 100)
queue:nil
usingBlock:^(CMTime time) {
// Establish the strong self reference
__strong typeof(self) strongSelf = weakSelf;
if (strongSelf) {
[strongSelf.timerDisp setText:[NSString stringWithFormat:#"%02d:%02d",min,current]];
} else {
// self doesn't exist
}
}];
I have read this article many times. This is an excellent article by Erica Sadun on
How To Avoid Issues When Using Blocks And NSNotificationCenter
Swift update:
For example, in swift a simple method with success block would be:
func doSomeThingWithSuccessBlock(success: () -> ()) {
success()
}
When we call this method and need to use self in the success block. We'll be using the [weak self] and guard let features.
doSomeThingWithSuccessBlock { [weak self] () -> () in
guard let strongSelf = self else { return }
strongSelf.gridCollectionView.reloadData()
}
This so-called strong-weak dance is used by popular open source project Alamofire.
For more info check out swift-style-guide
In another answer, Tim said:
you can't refer to self or properties on self from within a block that will be strongly retained by self.
This isn’t quite true. It’s OK for you to do this so long as you break the cycle at some point. For example, let’s say you have a timer that fires that has a block that retains self and you also keep a strong reference to the timer in self. This is perfectly fine if you always know that you will destroy the timer at some point and break the cycle.
In my case just now, I had this warning for code that did:
[x setY:^{ [x doSomething]; }];
Now I happen to know that clang will only produce this warning if it detects the method starts with “set” (and one other special case that I won’t mention here). For me, I know there is no danger of there being a retain loop, so I changed the method name to “useY:” Of course, that might not be appropriate in all cases and usually you will want to use a weak reference, but I thought it worth noting my solution in case it helps others.
Many times, this is not actually a retain cycle.
If you know that it's not, you need not bring fruitless weakSelves into the world.
Apple even forces these warnings upon us with the API to their UIPageViewController, which includes a set method (which triggers these warnings–as mentioned elsewhere–thinking you are setting a value to an ivar that is a block) and a completion handler block (in which you'll undoubtedly refer to yourself).
Here's some compiler directives to remove the warning from that one line of code:
#pragma GCC diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
[self.pageViewController setViewControllers:#[newViewController] direction:navigationDirection animated:YES completion:^(BOOL finished) {
// this warning is caused because "setViewControllers" starts with "set…", it's not a problem
[self doTheThingsIGottaDo:finished touchThePuppetHead:YES];
}];
#pragma GCC diagnostic pop
Adding two cents on improving precision and style. In most cases you will only use one or a couple of members of self in this block, most likely just to update a slider. Casting self is overkill. Instead, it's better to be explicit and cast only the objects that you truly need inside the block. For example, if it's an instance of UISlider*, say, _timeSlider, just do the following before the block declaration:
UISlider* __weak slider = _timeSlider;
Then just use slider inside the block. Technically this is more precise as it narrows down the potential retain cycle to only the object that you need, not all the objects inside self.
Full example:
UISlider* __weak slider = _timeSlider;
[_embeddedPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1, 1)
queue:nil
usingBlock:^(CMTime time){
slider.value = time.value/time.timescale;
}
];
Additionally, most likely the object being cast to a weak pointer is already a weak pointer inside self as well minimizing or eliminating completely the likelihood of a retain cycle. In the example above, _timeSlider is actually a property stored as a weak reference, e.g:
#property (nonatomic, weak) IBOutlet UISlider* timeSlider;
In terms of coding style, as with C and C++, variable declarations are better read from right to left. Declaring SomeType* __weak variable in this order reads more naturally from right to left as: variable is a weak pointer to SomeType.
I ran into this warning recently and wanted to understand it a bit better. After a bit of trial and error, I discovered that it originates from having a method start with either "add" or "save". Objective C treats method names starting with "new", "alloc", etc as returning a retained object but doesn't mention (that I can find) anything about "add" or "save". However, if I use a method name in this way:
[self addItemWithCompletionBlock:^(NSError *error) {
[self done]; }];
I will see the warning at the [self done] line. However, this will not:
[self itemWithCompletionBlock:^(NSError *error) {
[self done]; }];
I will go ahead and use the "__weak __typeof(self) weakSelf = self" way to reference my object but really don't like having to do so since it will confuse a future me and/or other dev. Of course, I could also not use "add" (or "save") but that's worse since it takes away the meaning of the method.

Why does setting self.object to nil cause a crash

In the following scenario I get a crash
if (self.videoEngine != nil)
{
[self.videoEngine.player.view removeFromSuperview];
[videoEngine release];
self.videoEngine = nil;
}
The videoEngine object is (nonatomic, retain), and it is synthesized using videoEngine = _videoEngine. If I remove the self.videoEngine = nil line the code works properly. Is this correct behaviour, and why does the nil line cause a crash? Would the self.videoEngine = nil still cause an issue within the viewDidUnload function?
When you call "self.videoEngine = nil;" it calls its setter method and in the setter method by default it releases the object and then it sets it to the value provided by you, so in this case you are releasing your object once and then setter method is trying to release it again that is causing crash, now if you remove the "[videoEngine release];" that would be fine and there will be no memory leak.
Hope it is clear now.
You should only release _videoEngine because that is the the synthesized name. videEngine is only the name of the setter and getter, but the value is stored in the syntheseized name. So your code should be:
if (self.videoEngine != nil)
{
[self.videoEngine.player.view removeFromSuperview];
[_videoEngine release];
self.videoEngine = nil; // Unnecessary
}
But you don´t need to call self.videEngine = nil after releasing the _videEngine because the setter will always return nil.
It is not considered a proper method of releasing by calling the setter method with nil, although it works, like is done with the line: self.videoEngine = nil; // Unnecessary.
The proper way of releasing is only [_videoEngine release];

EXC_BAD_ACCESS when messaging a valid object

My main app controller invokes a subcontroller to handle a certain sequence of screens. The main controller sets itself as a delegate in the subcontroller. When the subcontroller is done doing its stuff, it notifies the delegate. Every now and then, this notification fails with EXC_BAD_ACCESS.
0)Based on gdb, the problem occurs in objc_msgSend. Both registers have a non-zero value.
gdb: 0x3367cc98 <+0016> ldr r5, [r4, #8]
1)I've tried NSZombiesEnabled to track the problem, but I couldn't reproduce it then.
2)I've tried setting a breakpoint just before the problematic command, but again I can't reproduce the issue.
I have no clue what's going on.
This is the delegate property declaration (the parent controller outlives the child):
#property (assign) id<ParentControllerDelegate> delegate
This is the problematic code:
- (void) doStuff {
if(mode == Done) {
NSLog(#"Done. Handling back control");//this is the last log displayed by the console
[self.delegate done: self];
} else {
// some controller code
}
This is the the code on the delegate side (the delegate has been retained by the App_Delegate, as it is the main controller).
- (void) done: (UIViewController *) caller {
NSLog(#"Taken back control");// this never displays
[caller.view removeFromSuperview];
[caller release];
}
Some extra info:
The main controller retains the subcontroller.
I've also modified the deallocs in both the main and sub controllers to log when it is called. Based on the visible logs, neither is ever called during the course of the application. Hence both the receiver and the sender of the message are valid objects.
I'm really at loss here. Looking forward to your help.
If the NSLog call in done: is never performed, that can only mean that you did not call the main controller's done:. That can mean that self.delegate is not valid. The objects may be valid and alive, but not the link (self.delegate) between them. Check that, please. In doStuff, in the "Done" branch, show the address of self.delegate with
NSLog(#"%p", self.delegate);
before you call done: and compare that with the address of the main controller.
Just a wild guess, but if it's "now and then" it's probably viewDidLoad or viewDidUnload causing the EXC_BAD_ACCESS after receiving memory warning. Check your released/retained/created instance variables in your parent/child controller especially in aforementioned view loading methods.
Try to perform check protocol and method before call as in the code:
- (void) doStuff
{
if(mode == Done)
{
NSLog(#"Done. Handling back control");//this is the last log displayed by the console
if ([delegate conformsToProtocol: #protocol(ParentControllerDelegate)])
{
if ([delegate respondsToSelector: #selector(done:)] == YES)
{
[delegate performSelector: #selector(done:) withObject: self];
}
}
}
else
{
// some controller code

Set pointers to nil after release?

After releasing objects is it best to set the pointers to nil? Thats what I have been doing, just wanted to ask if its necessary, good practice or overkill?
- (void)dealloc{
[planetName release]; // NSString instance variable
[super dealloc];
}
#end
.
- (void)dealloc{
[planetName release]; // NSString instance variable
planetName = nil;
[super dealloc];
}
#end
cheers -gary-
Depends on the scope of the variable that holds the pointer. I always set pointers to nil if they continue to exist within the scope, just in case I'm calling the variable again somewhere else. Otherwise, there's a risk that I would access a memory location that contained an object which is now released.
But if the variable goes out of scope, then it won't be used either, thus assigning nil to it is a bit overkill. Still, it is a good practice to just assign nil just in case someone else decides to add code to your code and accidently uses the variable again within it's scope but after it was freed.
Usually when programming in C/C++ I set it to null. Why? Because even if you free the memory being pointed, the pointer still holds the address of that freed memory. It can cause a serious access violation problems in code like this:
if(myPointer != null)
{
doSomething(myPointer);
}
If you had set your pointer to null, this will never happen
It's considered good practice. If you set your pointers to nil after releasing them, then in case you misuse your variable at a later point of execution, you'll get a proper error.
At times this can be crucial, as I just found out. I use a camera in my game which keeps a pointer to a generic target. If you return to the main menu from a level then it clears the level from memory but keeps the camera and game layers.
-(void) dealloc {
[target release];
target = nil;
[super dealloc];
}
Since the camera will exist longer than the target, it's best to set target to nil, otherwise when the level loads again and you set a new target:
-(void) setTarget:(CCNode *)aTarget {
[target release];
target = [aTarget retain];
[self update:0];
}
It will crash on that release if the target is junk and not nil. Sending a message to nil is fine, but not to some arbitrary junk memory. That gives me a EXC_BAD_ACCESS.