I've got a custom class BoardMatchData, containing information about a chess match.
I've also got a custom UIViewController named BoardViewController, which is alloc'ed when a user selects a match from a list.
Here's a snippet from where I create the BoardViewController, set its delegate, and then set the new BoardMatchData:
Games *selectedGame = [[self fetchedResultsController] objectAtIndexPath:indexPath];
if (!self.bvc) {
NSLog(#"Alloc-ing a BVC");
self.bvc = [[BoardViewController alloc] init];
self.bvc.delegate = self;
}
[self.bvc setNewBoardMatchData:[MasterViewController boardMatchDataFromGame:selectedGame]];
When debugging, I can see this method setNewBoardMatchData being called, and it has valid data coming into it. However, later on within the BoardViewController, this boardMatchData always seems to be nil. Here's the setNewBoardMatchData method:
- (void)setNewBoardMatchData:(BoardMatchData *)newBoardMatchData {
NSLog(#"BMD is being set");
if (self.boardMatchData != newBoardMatchData) {
self.boardMatchData = newBoardMatchData;
[self configureView];
}
if (self.masterPopoverController != nil) {
[self.masterPopoverController dismissPopoverAnimated:YES];
}
}
And within BoardViewController.h, I just have an instance variable:
BoardMatchData *boardMatchData;
A method declaration:
- (void)setNewBoardMatchData:(BoardMatchData *)newBoardMatchData;
And then at the top of BoardMatchData.m, I have:
#interface BoardViewController ()
#property (strong, nonatomic) UIPopoverController *masterPopoverController;
#property (nonatomic,retain) BoardMatchData *boardMatchData;
- (void)configureView;
#end
#synthesize boardMatchData = _boardMatchData;
...my intent here was to make sure that the setter was only ever being called by itself, and not by some other object.
Is there something wrong with how I'm trying to set self.boardMatchData?
I'm not doing any retains/releases because I'm using ARC.
Edit:
Caleb - I did that #synthesize statement as part of my flailing around trying to find this bug. Originally I had:
#synthesize boardMatchData;
... which I just switched back to. The behaviour is the same; self.boardMatchData always ends up nil, even after I've set it.
I think now I have only one ivar, boardMatchData, and I'm always accessing it through self.boardMatchData.
How do I prevent this from becoming nil?
#synthesize boardMatchData = _boardMatchData;
This says that the ivar the accessors should use is _boardMatchData, but you've also got an ivar named boardMatchData. If you're using the accessors, only _boardMatchData will be set. Since Objective-C automatically clears any ivars when your object is created, theboardMatchData ivar will always be nil.
Your comment (that you posted as an answer which you shouldn't do) suggests that you work on two different instances.
Here are a couple of possible reasons for this:
self.bvc is just assign property instead of retain.
You load one from within a nib and one is constructed in your code
(as shown) - this is probably the most like one. Maybe you just
forgot to wire up the outlet.
Your set self.bvc to nil somewhere so that you keep creating new
instances.
Aha; I found this question with an almost identical problem:
Objective-C – Retained property after being set is nil?
There was no conclusion to that one, but the last suggestion was to "try logging the address of self in -viewDidLoad and -viewWillAppear and -queueFinished. Something like NSLog(#"self is %p", self); and making sure they are the same."
I did that myself and now see that in initWithNibName/configureView/setNewBoardMatchData, I'm seeing one pointer for self, and then when viewDidLoad runs, I'm getting a different one!
I'm not sure how or why yet, but this clearly appears to be the problem (a new instance of my class is being instantiated AFTER I've set boardMatchData).
Edit:
While the above led me to the path of finding this bug (I was getting multiple versions of my BoardViewController), it's not the complete answer. I wanted to add here should anyone find this and be in the same position.
I was actually using storyboarding in Xcode4, and the Apple provided master-detail template with Core Data.
When I was instantiating my detail controller (BoardViewController), I was doing an alloc/init. I should have simply been referencing [segue destinationViewController], as the segue already instantiated a version for me.
I did not provide enough context to actually get to the root
Related
I am going to paste a code here and had a question regarding that which I wanted to understand merely, based on the logical way.
#interface MySingleton : NSObject {
NSString *enteredCode;
}
#property (nonatomic, retain) NSString *enteredCode;
#end
#synthesize enteredCode;
-(void) addInput:(NSString *) input
{
self.enteredCode = [self.enteredCode stringByAppendingString:input];
}
- (void)dealloc {
[enteredCode release];
}
#end
In my code, if I utilize "self.enteredCode = [self.enteredCode stringByAppendingString:input];"
everything works fine but "enteredCode = [self.enteredCode stringByAppendingString:input];" it gets exc_bad_access, and I am just wondering why this case be?
I am just trying to understand what difference really does it makes without having self there?
Thanks.
This is not to do with singletons. When you do self.enteredCode you are going through the property which is set to 'retain'. The stringByAppendingString method is a convenience method with returns an autoreleased object to you, meaning that it will be released at some point on the next run loop. You need to retain this value to stop it being released, which is fine when you assign it through the property as it is properly retained by you and you can use it as you like.
When you reference the variable directory (without the self.) you bypass this and as such you don't ever retain the value, the value is subsequently released and you reference bad memory and BOOOOOOOOM, bad access.
when you call self.enteredCode = XXX it will call [self setEnteredCode:XXX]. Since you are using a retain property this will release the old value of enteredCode, and retain the new value.
if you directly manipulate the enteredCode variable you will have memleaks and crashes because it will try to release something that is not retained later.
If I understand correctly, self.enteredCode works but enteredCode fails.
If that's the case then I believe it's because you're bypassing the property and setting the iVar directly. That means you're assigned an auto released object and bypassing the retain mechanism.
Consider using something like _enteredCode for your iVars do it's clearer in your code when you're bypassing properties.
MyGems.h
#import <UIKit/UIKit.h>
#interface MyGems : UIViewController {
IBOutlet UIImageView *lock1;
Collect.m
#import "Collect.h"
#import "MyGems.h"
#implementation Collect
- (IBAction) unlock {
if (lock1.hidden = NO) {
ruby.hidden = NO;
}
I get 4 errors, can someone please help? It seems to simple, but is confusing me.
You should almost never do this. The view controller (MyGems, which should be named something like MyGemsViewController) is responsible for managing this view. Other classes should not reach in and modify its IBOutlets. Doing so will cause you significant problems when the view managed by MyGems unloads and lock1 surprisingly becomes nil.
It's unclear what Collect is in this case; I assume it is another view controller? I'm not clear why unlock isn't a method on MyGemsViewController.
Also note that this code is incorrect, and should be throwing warnings at you telling you it's incorrect:
if (lock1.hidden = NO) {
This assigns NO to lock1.hidden. You meant to use ==, but you should never test against NO this way. You should do it this way:
if (! lock1.hidden) {
You must be careful of testing booleans against YES and NO. There are many true values that do not equal YES.
You need to make sure you have a reference to lock1 in your Collect class, most likely you will want to achieve this by having a reference to the Collect class in MyGems and then moving this view logic back into MyGems rather than in your Collect model class
I got the "objc_msgSend()" killer error message in my app and thanks to Hamster Emporium
i can figure out a little bit what was happening.
Now i found the "problem" and the "solution", but what i can't understand why my problem was really a problem.
Here is the scenario:
Object_A --> Object_B --> Object_C
The '-->' symbol represent the "create" action.
Class of Object_C looks like this:
#interface Class_C {
NSArray *items;
}
#property (nonatomic, retain) NSArray *tems;
#end
The property 'items' is set in Object_B through a 'setItems' method:
- (void)setItems:(NSArray *)items_ {
if (object_B) {
[object_B.taskItems release];
object_B.taskItems = items_;
}
[super setItems:items_];
}
Now, if I use this method as is I got the blasphemous 'objc_msgSend()' error BUT if I comment the release line everything goes well.
Note: the retainCount in the release line is 0, but the release execute without problems
You are getting that error because the taskItems member variable is being released twice. There is no need to manually release taskItems because using the dot syntax takes care of it automatically.
This line:
object_B.taskItems = items;
Invokes the property accessor for taskItems, in which the old value is automatically released before the new one is retained (or copied, depending on the property definition).
A very good general rule for Cocoa memory management is that you should only release an object if you created it (either by alloc/init or by copy). Releasing object_B.taskItems would violate that rule.
Uhm, wow. ok.
object_B.taskItems = items_;
is the same as calling
[object_B setTastItems: items_];
if taskItems is a property set to retain, you don't need to release it first since the property will do so. The way you have your code right now, it gets released twice.
Remember, properties are not the same as members in Objective-C. Properties are methods which access the private members of the class (and do fancy stuff like retain/release and #synchronized).
I had a similar problem, but in my case this was the scenario:
I made a controller that registers itself to listen for changes in a NSOperation attribute "isFinished", while the NSOperation was working my controller went away, when the NSOperation finished and tried to notify:
[self willChangeValueForKey:#"isFinished"];
I got
objc_msgSend() corrupt cache error
But it was because my Controller was out of scope, to fix it I wait for the results of NSOperation KVO and then move to next controller.
When using property/synthesize for a UITableView, UIButton, etc should self be included in the method call on that variable? Using UITableView as an example is there a difference between [self.myTableView visibleCells] and [myTableView visibleCells]? Or say [self.myImage setImage:...] and [myImage setImage:...]?
I've seen Apple code that does use self (Bubble Level) and examples in the book Beginning iPhone Development that do not use self. I'd like to understand this better, especially since using self in my UIScrollView method calls has caused erratic/buggy scrolling behavior. Thanks.
Using self.myTableView is another way of saying [self myTableView] (it can also be [self setMyTableView:...]; if used in an assignation statement). In other words, you're executing a method.
Using myTableView accesses the instance variable directly.
Personally, I generally prefer using the former method, since it usually frees me from manually managing memory and gives me the benefit of KVO notifications. However, there is the miniscule overhead of the extra method call, which you may wish to avoid.
Which style you choose to use is up to you, and each way has its benefits and disadvantages.
The difference comes down to how you define the property. For example, say you have the following:
#interface MyObject : NSObject {
NSObject *memberVariable;
}
#property (nonatomic, retain) NSObject *memberVariable;
#end
#implementation MyObject
#synthesize memberVariable;
#end
Specifying (nonatomic, retain) actually tells #synthesize how to create the getter and setter methods. Specifying retain causes the setter method to call retain on objects I pass to it. So, self.memberVariable = someOtherObject is equivalent to memberVariable = [someOtherObject retain];
This is also why you should never do self.memberVariable = [[NSObject alloc] init]; if you've specified retain in the property definition. alloc initializes the retain count to 1, passing the object to the setter method increases the retain count to 2.
This comes down to whether or not your accessor methods have custom behavior, in which case you'd always want the accessors called even from within the class, and whether you want to make sure KVO notifications are generated. If you're using stock accessors (e.g., synthesized) and it won't affect anything to access the instance variable directly from within the class, you're saving yourself a method call.
I was looking at some sample code on Jeff LaMarche's excellent blog when I came across the following:
- (void)applicationDidFinishLaunching:(UIApplication*)application
{
CGRect rect = [[UIScreen mainScreen] bounds];
window = [[UIWindow alloc] initWithFrame:rect];
GLViewController *theController = [[GLViewController alloc] init];
self.controller = theController;
[theController release];
// ...
}
In the .h, we see that "window" and "controller" are ivars declared as so:
#interface OpenGLTestAppDelegate : NSObject
{
UIWindow *window;
GLViewController *controller;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet GLViewController *controller;
#end
My question is: Why are "window" and "controller" assigned in different ways?
I think I understand why each kind of assignment works (keeping track of retain count), but why are they assigned in different ways? Specifically, why isn't controller assigned in the same way window is with a single line like so without going through the setter:
controller = [[GLViewController alloc] init];
In general, when would you use the single line method and when would you use the multiple line method?
Thanks.
Does he create a custom setter for the controller instance variable?
If so, there may be code which is called when the controller variable is changed through the setter. Merely setting the controller variable with:
controller = [[GLViewController alloc] init];
would not invoke the setter method; however, assigning the newly allocated object to a local variable then setting it with:
self.controller = theController;
would invoke the setter method since it is a shorthand way of writing:
[self setController:theController];
and the extra code in the setter would be executed. This is commonly where you would expect the differentiation between the two methods.
Edit:
Evidently, after taking a look at the code, he doesn't implement a custom setter method, however the method that he has used is still most commonly used when a custom setter method would be implemented.
My guess at the reason behind the extra code would be that he plans to release the variable after allocation, and if assigned to a local variable, he can call the setter method with the local variable and then call release on the local variable afterwards. This would be overall more readable than using
[[self controller] release]
However, it is an odd way to do it, as the synthesized implementation of the setter will retain the instance variable, yet he then releases it once it has been set to the instance variable, and as the release call cancels out the retain call, it would make more sense to set the variable using the one-line method.
The extra code seems to be just because he specifically wants to use the property (setter method). In his implementation (GLView.m), -setController also sets a boolean ivar based on whether the controller responds to (implements) the -setupView: method.
Even so, it would seem that a one-line solution would work just as well:
self.controller = [[[GLViewController alloc] init] autorelease];
The same line as an explicit message send (without dot syntax) works as well:
[self setController:[[[GLViewController alloc] init] autorelease]];
Either approach will leave the new controller with the proper retain count, and still uses the setter property as desired.
(Note: The code in question is linked at the end of this blog post.)
Edit:
Sorry for any confusion. The code has a "GLViewController *controller" ivar and property both in ___PROJECTNAMEASIDENTIFIER___AppDelegate.m and GLView.m, and I was looking at the latter. (In the former, the setter is indeed synthesized, and it will retain the controller. On lines 77-81, you can see the code I mentioned, and he doesn't actually retain the controller — only the AppDelegate retains it.)
In the app delegate code, the synthesized setter will retain the GLViewController, so my one-line replacement advice still stands. One can argue both ways about readability, but for those who understand the retain-release idiom well, I would suggest that the one-line version is much more readable. It communicates the intent succinctly, and even provides an implicit hint that the setter will retain the controller. The extra local variable is really just unnecessary fluff.
As Quinn pointed out, the assignment to the controller ivar may be written in one line using autorelease method. The reason to use more verbose version is exactly to avoid autorelease and use manual release instead. This is due to Apple recommendation to minimize the use of autorelease pools on iPhone. So you must store the reference to the newly allocated object in a local variable to release it after a call to setter.
Considering the question when to use direct assignment to an instance variable (as in the case of window ivar) and when to use a setter method (as in the case of controller ivar), it is mostly a question of style, but you better be consistent.
There are two styles of ivar setting:
Always use direct assignment to an ivar. Switch to setter methods only for ivars for which setter must perform some additional work beside assignment.
Always use setter methods for all ivars.
Personally, I think that use of the second style results in more consistent and maintainable code. If some day you realize that your setter must perform more work you should change only the setter, while when using the first style you also should change all occurrences of direct assignment to the setter call.
Just found the good discussion of the issue in another thread: instance variable/ method argument naming in Objective C.