accessing variable - iphone - iphone

I have a NSMutableString var, which I have also synthesized.
This gets set in viewDidLoad
NSLog(#"Var val is %##",curr_rep_date);
I have a button on which i call an IBAction and am trying to access the var value inside this method.
-(IBAction) moreDetails{
NSLog(#"INSIDE IBACTION var val is %#",curr_rep_date);
}
But for some reason, the app crashes (Program received signal: “EXC_BAD_ACCESS”.)
Please help me fix the issue,

are you sure you either use the setter (which hopefully retains the object) when you create the object or create a not autoreleased object?
choose one.
self.curr_rep_date = [NSMutableString string];
curr_rep_date = [[NSMutableString alloc] init];

You're probably storing an object you don't own in an instance variable, so when you try to get at it again later, it's gone because it didn't know you needed it.
The memory management guide offers a simple set of rules you need to follow to get this right.

Related

When to use properties and allocation initializing

I was just working on my application where I needed to set an instance variable of NSMutableData a value. Now I also created a property for my instance variable which means that my program automatically allocates it etc, right? But then I assigned it a value but it was not taking it but staying null. I then manually allocated it and then it suddenly accepted the value. So now my question is what is the need for properties and why do I have to manually allocate my instance variable although I have a property set up for it?
Thanks in advance!
edit: my code:
in my .h file I have
#interface FirstScreen : UIViewController{
NSMutableData* fetchedData;
}
#property(nonatomic, retain)NSMutableData*fetchedData;
in my .m file I have:
-(void) connectionDidFinishLoading:(NSURLConnection *)connection{
NSString* fetchedDataString= [[NSString alloc]initWithData:fetchedData encoding:NSUTF8StringEncoding];
}
Now if I do not implement:
-(void)viewDidLoad{
self.fetchedData=[[NSMUtableData alloc]init];
}
fetchedDataString does not have any value. However if it is allocated it has a value. I am confuces when to allocate instance variables and when not to.
It doesn't allocate. All properties do for you is define the instance variable & implement accessor methods.
I'm assuming by "assigning a value" you mean trying to set the contents of the NSMutableData object you thought had been allocated for you.
Now I also created a property for my instance variable which means
that my program automatically allocates it etc, right?
Wrong. If you synthesize accessors for the property, an ivar will also be created for it if you haven't created one. But your property is just a pointer... it doesn't point to anything until you create an object for it to point to, and set it:
self.fetchedData = [[NSMutableData alloc] init];
That's C. What you're saying is true for every single variable, whether it's local or an instance variable. It's one thing to declare storage for a variable (that's all you're doing by declaring a property). It's another to give it a value. This declaration in code:
NSMutableArray* arr;
...does not cause arr to take on any particular value (under ARC it's nil; prior to ARC it could be anything at all). It is certainly not an empty mutable array! But that's exactly analogous to what you're doing when you declare a property.
If this is the first value the variable is to adopt, that's called initializing. You might say in code:
NSMutableArray* arr = [NSMutableArray array];
But you can't do that in a property declaration, so you have to initialize at some later time while the code is running. A typical approach is to do this in your designated initializer, so that no matter what happens later there will be an actual array at this address, from very early on.
I've written a book on this topic (iOS programming), and the chapter dealing with the issue you're having is free to read online:
http://www.apeth.com/iOSBook/ch03.html

iOS observeValueForKeyPath not getting called

I had a problem getting observeValueForKeyPath to be called but solved it using this:
observeValueForKeyPath not being called
However, I'd like to know how to handle this in general for future reference.
The code that works looks like this:
- (void) input: (NSString*) digit
{
NSLog(#"input() - Entering... digit=%#", digit);
if ([digits length] < MAX_DIGITS_LENGTH)
{
self.digits = [[[ self.digits autorelease] stringByAppendingString:digit] retain];
NSLog(#"digits is now %#", digits);
}
}
Prior to this I was using an NSMutableString instead of NSString and just said used appendString. I didn't do an assignment and I wasn't appending "self" to the digits variable. Are there any good websites/tutorials that explain this more in depth so I know how to do this in general for any type of object?
KVO works by method swizzling and notifying on value changes. If you access your properties with out self then you are accessing an iVar directly and not using the method. When not using a method there is no way to send KVO notifications to your observer. The other issue you ran into is mutable vs immutable data. When you are appending a string you not changing the object but you are changing the data it is pointing at and that is why you were not getting any notifications. Only the get accessor was being called to get the string then you were calling append data on that.
Your memory mgmt seems off. Assuming 'digits' is a #property declared with the retain or copy attribute, and you are using the synthesized setter (or wrote an equivalent one yourself), then you should use the setter like this:
self.digits = [self.digits stringByAppendingString:digit];
You shouldn't autorelease the old value or retain the new one, since the setter does that for you.
If you would like to use an NSMutableString there instead, you could trigger the KVO notifications manually like so:
[self willChangeValueForKey:#"digits"];
[self.digits appendString:whatever]; // assumes digits is a mutable string now
[self didChangeValueForKey:#"digits"];
Hope that helps.

Syntax for accessing instance variables? (Objective-C)

What is the proper syntax for accessing an instance variable in Objective-C?
Assume we have this variable:
#interface thisInterface : UIViewController {
NSMutableString *aString;
}
#property (nonatomic, retain) NSMutableString *aString;
and that it is synthesized.
When we want to access it, we first would want to allocate and initialize it. Having programmed in Objective-C for about a month now, I've seen two different forms of syntax. I've seen people do simply aString = [[NSMutableString alloc] initWithString:#"hi"], where they allocate the string like that; I've also seen people start it off with self.aString and then they proceed to initialize their ivar. I guess I'm just trying to figure out what is the most proper way of initializing an instance variable, because with the former example, I have received EXC_BAD_ACCESS errors from it. After prepending the self. though, it didn't appear.
Forgive me if this is a duplicate question, but after reading some posts on SO, it's made me curious. I'm trying to learn the proper syntax with Objective-C because I prefer being proper rather than sloppy.
If you have declared a property and #synthesize it in the .m file, you simply set it like this:
self.aString = #"hi"; // or [[NSMutableString alloc] initWithString:#"hi"];
Using self.varName takes advantage of what your property declaration actually does- it handles retention of the new value (since your property has the retain attribute), releasing the old value, etc for you.
If you just do:
aString = someValue;
... you may be leaking the original value that was in aString, since without using self.aString you are accessing the variable directly vs through the property.
Note the difference between self->varName and self.varName
The first is pointer access. The second is property access.
Why is that important? Pointer access is direct. Property access, on the other hand makes use of getters and setters (be they #synthesized or not). Moreover, as a convenience, the #synthesized accessors take care of the memory mangement for you (i.e. when using self.varName = ...;), whereas varName = ...; does only what it says, i.e. the assignment -> (there lies the explanation for EXC_BAD_ACCESS errors you might be getting).
Syntactically, both forms are correct. If you want to better communicate intent, use self->varName when you want to work directly with the pointer and use self.varName when you want to take advantage of the #property convenience.
Here are all the possible combinations (I think)
OKs and BADs are only correct when aString property has retain attribute:
#property (nonatomic, retain) NSMutableString *aString;
So:
1
aString = [[NSMutableString alloc] init]; //OK:
This is OK but only in the case aString is not pointing to an invalid object or you will loose a reference to that object and it will leak because you won't be able to reach it to release it.
2
aString = [NSMutableString string]; //BAD
Bad because you are suppose to retain aString (as you declared it that way), you are not retaining it and you will get surely get EXC_BAD_ACCESS in the future
3
aString = [[NSMutableString string] retain]; //OK
Same as the first approach, only good if aString is not pointing to a valid object. However I will use the first though.
4
aString = [[[NSMutableString alloc] init] autorelease];//BAD
Same as the second approach.
5
self.aString = [[NSMutableString alloc] init]; //BAD!!
Bad because you are retaining it twice, hence it will lead to memory leaks
6
self.aString = [[NSMutableString string]; //******GOOD!******
This is probably the safest. It will be retained by the property setter and since you are using the setter any other object that could have been pointed by aString will be released appropriately
7
self.aString = [[NSMutableString string] retain]; //BAD
This is retained twice.
8
self.aString = [[[NSMutableString alloc] init] autorelease];//Ok
This is also OK, but I would use the convenience method instead of this long approach :)
Be wary that the #1 and #3 options are perfectly good if you know what you are doing. In fact I use them much more frequently than #6
I personally prefer to use the self. syntax. It just makes it easier to determine that its an instance variable, and not just some other variable in the current scope that will be lost when its NSAutoreleasePool is drained. However, it is correct to use them both ways, and if you are receiving EXC_BAD_ACCESS errors, it is not because you accessed it without using self.. You are correct in saying that you must alloc it, and whichever way you choose to access your variables, keep it consistent or you will receive errors.
I hope this helps.
Always use accessors except in init, dealloc and in accessors themselves. Doing this will save you a lot of headaches like the one you're describing. Also, name your ivars something different than your property (_foo, foo_, mFoo, but not foo).
self.foo is precisely the same as [self foo]. I calls the method foo. self.foo = x is precisely the same a [self setFoo:x]. It calls the method setFoo:. If you synthesized the property foo as a retain variable, then this looks something like:
#synthesize foo = foo_;
- (void)setFoo:(id)value {
[value retain];
[foo_ release];
foo_ = value;
}
This correctly releases the old value of foo_, assigns a new one and retains it.
foo = x (assuming foo is an ivar) does not call any method. None. It just assigns the value of the pointer in x to the pointer in foo. If foo pointed to something that was retained, it's leaked. If the new value you're assigning isn't retained, you'll crash later.
The solution to this is to always use accessors when you can.
Either.
Using the dot syntax is cleaner (to some) and it compiles to the equivalent. i.e self.iVar is the same as [self iVar] and self.iVar = aValue is the same as [self setIVar:aValue];
self.aString is a syntactic sugar to [self aString]. Synthesize a property just create the -aString and -setAString: method (depending on the property you have chosen it while not be the trivial affectation).
Now the question is whether to use the . notation. I suggest you not to use it.
Why? First know that Objective-C aim to be just an addition to C. This mean that every valid C code is also a valid Objective-C code.
Now look at what they have done with the dot notation. The last statement does not hold anymore. You wont distinguish between an access to a field of a C structure and sending objective-c method.
So please don't use the dot notation. Prefer using the [self ..].

Where to initialize an instance variable in a class

I'm new to objective-c and I always have problem with global variable . I don't know where to initialize them . My problem is with an NSString . I wrote this code –
in .h
NSString *session ; // i also #property(retain,nonatomic) and synthesize ...
in viewDidLoad , '
session=#"HEllo";
and in
-(IBAction) showInformations:(id)sender;
{
NSLog(#" informations ok");
NSLog(#"my sesison : %# ",session);
}
But I have a crash in show information :/ session is empty I think . Help please
session = #"hello";
self.session = #"hello";
There is a huge difference between the above two statements. The first one just assigns hello to session. Here the string hello is autoreleased, so session is not valid when you tap the button, as you have not retained session. But in 2nd line self is used. When self is used, it is not just a simple assignment, it is actually a call to accessor method. Here you have used retain in property declaration. So when self is used, the setter for session is called which retains it. So session is valid when you tap the button.
The summery is use right property and use self to avoid many memory problems.
EDIT: As pointed by fluchtpunkt, this explanation is not valid for string literals. I was out of my mind that string literals are special when writing this.
Try setting it using the dot syntax for a property:
self.session=#“Hello”;
This will ensure proper memory management.
There must be another write access to session somewhere in your code. A line of code that looks like session = [NSString stringWith...];
So find the other parts of the code where you assign something to the session variable and replace the wrong memory management over there with proper memory management. The problem is not within the three lines you have shown.
Depending on your code it should be something like
self.session = [NSString stringWith...
or if you like it inconvenient
[session release];
session = [[NSString stringWith...] retain];

Why am i getting a EXC_BAD_ACCES

Hey. I have been working on a Twitter application and have been stuck on a EXC_ BAD_ ACCESS error for quite some time. I know that EXC_ BAD_ ACCESS is a memory issue but i cannot pinpoint where the problem is. Here is my code sample:
- (void)viewDidLoad {
[super viewDidLoad];
NSString *path = #"/Volumes/Schools/BHS/Student/740827/Documents/Forrest McIntyre CS193P/Presence2";
NSArray *propList = [NSArray arrayWithContentsOfFile:[NSBundle pathForResource:#"TwitterUsers" ofType:#"plist" inDirectory:path]];
people = [[NSMutableArray alloc]init];
for (NSString *name in propList) {
Person *p = [[Person alloc] initWithUserName: name];
[people addObject: p];
[p release];
}
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
The exception is thrown on the last brace after the comment. I believe that it is truly thrown in the for loop somewhere but just shows up upon exiting.
Here is the implementation file for Person:
#implementation Person
#synthesize image;
#synthesize username;
#synthesize displayName;
#synthesize statusArray;
-(id)initWithUserName:(NSString *)userName {
if(self = [super init])
{
self.username = userName;
NSDictionary *info = [TwitterHelper fetchInfoForUsername:userName];
self.displayName = [info objectForKey:#"name"];
NSLog([NSString stringWithFormat:#"%#",[info objectForKey:#"profile_image_url"]]);
NSString *imageURL2 = [NSString stringWithFormat:#"%#",[info objectForKey:#"profile_image_url"]];
self.image = [UIImage imageWithData: [NSData dataWithContentsOfURL: [NSURL URLWithString: imageURL2]]];
[info release];
self.statusArray = [TwitterHelper fetchTimelineForUsername:userName];
}
return self;
}
#end
Thanks for any help
EDIT: Here is the header file for PersonListViewController (the class that contains the ViewDidLoad).
This is just to show you where people is coming from.
#interface PersonListViewController : UITableViewController {
NSMutableArray *people;
}
#end
since you never retain propList or path you shouldn't be releasing them.
You should, however, release people
For an overview of memory management, see the Memory Management Programming Guide
For quick fixes, try the static analyzer.
I think the problem is here:
[propList release];
Since you created propList using arrayWithContentsOfFile you don't need to release it - it will be automatically released. The autorelease is actually what's causing the error since it is trying to release something that you already released manually.
ETA: as cobbal mentioned, you also don't need to release path.
Debugging EXC_BAD_ACCESS is difficult to debug. This happens when a message is sent to an object that is already released. You need to find out what is causing this generic error by turning on NSZombiEnabled environment variable so the Objective-C environment will be able to 'track' a deallocated object. Using this, when you get the error you can determine where the error occurred by looking at the call stack. You won't know where it is released but at least it will get you close.
I don't have it setup here, but you may also be passing a pointer to the error which will cause the object to not persist as a zombie/dummy.
Bottom line, you need to make sure the variables you are meaning to release, that you retain them as necessary.
This Technical Q&A by Apple gives tips on Finding bugs with EXC_BAD_ACCESS.
For one, neither of these are necessary in your example:
[path release];
[propList release];
because:
path is a string literal (will always exist)
propList is autoreleased
For any EXC_BAD_ACCESS errors, you are usually trying to send a message to a released object. The BEST way to track these down is use NSZombieEnabled.
This works by never actually releasing an object, but by wrapping it up as a "zombie" and setting a flag inside it that says it normally would have been released. This way, if you try to access it again, it still know what it was before you made the error, and with this little bit of information, you can usually backtrack to see what the issue was.
It especially helps in background threads when the Debugger sometimes craps out on any useful information.
VERY IMPORTANT TO NOTE however, is that you need to 100% make sure this is only in your debug code and not your distribution code. Because nothing is ever released, your app will leak and leak and leak. To remind me to do this, I put this log in my appdelegate:
if(getenv("NSZombieEnabled") || getenv("NSAutoreleaseFreedObjectCheckEnabled"))
NSLog(#"NSZombieEnabled/NSAutoreleaseFreedObjectCheckEnabled enabled!");
If you need help finding the exact line, Do a Build-and-Debug (CMD-Y) instead of a Build-and-Run (CMD-R). When the app crashes, the debugger will show you exactly which line and in combination with NSZombieEnabled, you should be able to find out exactly why.
http://www.cocoadev.com/index.pl?NSZombieEnabled can be useful in tracking down EXC_BAD_ACCESS bugs. Instead of deallocating objects when they are released it puts them into a zombie state that raises an exception when they are subsequently accessed. Just be sure not to ever release code with this flag set, as it will leak memory like a sieve.
what is self.editButtonItem? I don't see it in your .h file
A couple of things.
In initWithUserName: you're getting info from a method that doesn't contain alloc/copy/create. Further, you don't explicitly retain it. Yet you release it. This is problematic assuming fetchInfoForUsername: autoreleases its result as expected according to the Cocoa Memory management rules.
Using property accessors in initializers is considered bad form since it can cause KVO notifications to be sent out for a half-baked instance.