iPhone SDK - instance variable out of scope issue - iphone

I am getting crazy over this error. Compiler is saying out of scope for an instance NSSString variable. Never had this thing before and used thousands of NSString instance variables!
Here is my class .h file
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <CoreAudio/CoreAudioTypes.h>
#import "Snapshot.h"
#interface RecordAudioViewController : UIViewController <AVAudioRecorderDelegate, AVAudioPlayerDelegate> {
NSString *filename;
}
#property (nonatomic, retain) NSString *filename;
- (IBAction) recordAudio;
- (IBAction) playAudio;
#end
Variable is synthesized properly. I initalize filename variable in viewDidLoad method. I want to use it in IBAction method recordAudio, but compiler always says out of scope? Why is that, is this a bug or something?
Here is .m code. viewDidLoad method where I set the filename instance variable:
- (void)viewDidLoad {
[super viewDidLoad];
NSString *tmpDir = NSTemporaryDirectory();
filename = [NSString stringWithFormat: #"%.0f.%#", [NSDate timeIntervalSinceReferenceDate] * 1000.0, #"caf"];
NSLog(filename);
}
And the IBAction method
- (IBAction) recordAudio
{
NSLog(filename); // here I get out of scope message when moving over with mouse cursor and when steping over this line EXC_BAD_ACCESS
}
The entire .m file can be seen here: http://pastie.org/1021993

Actually, if you set filename = [NSString stringWithFormat...], the autoreleased result is NOT retained.
However, if you use self.filename = [NSString stringWithFormat...] it WILL retain the string. Kinda looks like the string is getting released out from under you because you're not retaining it.

You mentioned that you initialize the variable filename in the viewDidLoad method. if you mean nsstring alloc and init methods by initializing, i don't think that you are going the right way. It is not necessary to initialize a synthesized string, or more generically any strings. I'm not sure whether you meant this by initializing, but i gave my opinion based on the idea that i got from your Ques.

Is viewDidLoad actually happening? If it doesn't get called, that would perfectly explain the crash in recordAudio as it hasn't been initialised.

Related

Accessing NSString between methods causes app crash

I apologise if this is a bad question as I'm new to iOS development. So here is my problem: I declared a class variable NSString, the string is assigned a string value from a textView but when i try to access the string from other method, the app crashes. Here's the code:
Interface: (ClassName.h)
#interface ClassName: UIViewController <UITextViewDelegate>{}
#property (nonatomic, assign)NSString *strSomeText;
#end
Implementation: (ClassName.m)
#implementation
#synthesize strSomeText;
- (void)textViewDidChange:(UITextView *)textView{
strSomeText = textView.text;
NSLog(#"%#", strSomeText); //This line works just fine
}
- (void)textViewDidEndEditing:(UITextView *)textView{
NSLog(#"%#", strSomeText); //this line causes the app to crash
}
#end
Thanks for the help!
Loc.
Your problem is likely due to the fact that you're using assign for your property. This will mean that the string can be deallocated while you still have a reference to it. Try using copy instead:
#property (nonatomic, copy) NSString *strSomeText;
Then you should use your property accessor in your textViewDidChange: method:
self.strSomeText = textView.text;

How To Read TXT File From A Server

Here is the complete .m file :
#import "DevotionalView.h"
#implementation DevotionalView
#synthesize mytextview;
#synthesize mystring;
- {void} awakeFromNib {
NSURL *myurl = [NSURL URLWithString:#"http://www.myserver.com/text.txt"];
NSString *mystring = [NSString stringWithContentOfURL:myurl];
mytextview.text = mystring;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
The errors are: '#end' is missing in implementation context --where the #implementation DevotionalView is-- and at the {void} line it says Expected selector for objective-c method.
Thanks for taking the time to help!
The errors are: '#end' is missing in implementation context --where the #implementation DevotionalView is-- and at the {void} line it says Expected selector for objective-c method.
Also, at the end of the file it say "expected method body"
Seems to work fine in the tutorial I followed, but it will not compile in XCode 4.3.
I'm using Storyboard-- will this change the part about NIB? I apologize for my lack of knowledge-- still getting used to this.
Thanks for any help!
It looks like you have {}'s around the void in awakeFromNib they should be ()'s
Well, I finally worked around it-- from my searches it would appear that I had either messed up a delegate assignment or some such thing. So...(and you pros might groan at this) I opened up a new project (single view with a controller) and copied and pasted the controller, .h and .m files in, then used this code:
- (void)viewDidLoad
{NSError *error = nil;
NSURL *myurl = [NSURL URLWithString:#"http://www.myserver.com/test.txt"];
NSString *mystring = [NSString stringWithContentsOfURL:myurl encoding:NSUTF8StringEncoding error:&error];
newtext.text = mystring;
All is well!

Access to variables through delegate

I've go a situatiion in Objective-C where I'm trying to access an object's variable through another object. The classes (simplified):
A.h
#interface A : NSObject {
NSMutableArray *someStuff;
}
#property (nonatomic, retain) NSMutableArray *someStuff;
#end
A.m
#implementation A
#synthesize someStuff;
// blah, blah, blah
Then, because I'm doing an iPhone app, there is an app delegate that contains a variable of this object type:
AppDelegate.h
#interface AppDelegate : NSObject <UIApplicationDelegate> {
A *aPtr;
}
#property (nonatomic, retain) A *aPtr;
#end
AppDelegate.m
#implementation AppDelegate
#synthesize aPtr;
// blah, blah, blah
Then, in another class (in this a view controller), I'm trying to access 'someStuff' in this manner:
AViewController.m
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSMutableArray *someArray = appDelegate.aPtr.someStuff;
So, the problem is that this blows up in fine fashion. I think I'm too much of a Java junkie to understand why this won't work. Can anyone elighten me?
Many thanks,
Craig
You need to initialize this in this way
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
NSMutableArray *someArray = appDelegate.someArray;
This will resolve your problem.....
Craig,
appDelegate.aPtr will return null. as it is not initialized yet, and when you try to access some member of a null object,(in java NULLPointerException).Its behavior is as expected.(this blows up in fine fashion).
Thanks,
Ravin is correct. The class definition defines the iVars and properties for a class so you have defined an iVar aPtr that references an object of type A. However, you have not allocated and initialized this object.
An example using the default initialization would be `aPtr = [[A alloc] init]'.
This all sounds suspicious since in ObjC you are allowed to send messages to nil without a problem and properties are just diguised methods. For example you can
view = nil;
view.hidden = NO;
and it doesn't blow up, it just does nothing.
So since appDelegate.aPtr.someStuff is just
[[appDelegate aPtr] someStuff];
and [appDelegate aPtr] does nothing and returns nil so it should be safe to call [[appDelegate aPtr] someStuff] without a problem but also without any results.
So while it is a problem with using objects that hadn't been initialized (which most often should be done in a designated constructor of the appropriate object), since you don't get results that you expect, in my undestanding of "sending message to nil" in ObjC it shouldn't blow up. If it is then either I am missing the point or something other causes the problem and not this call.
EDIT
just checked: if not initialized at all it works as I explained: ObjC allows messages to be sent to nil:
A *aPtr = appDelegate.aPtr;
NSMutableArray *someArray = aPtr.someStuff;
NSLog(#"%#", someArray);
or
NSMutableArray *someArray = appDelegate.aPtr.someStuff;
NSLog(#"%#", someArray);
both don't break and print null.
If you initialize A properly but not initialize someStuff in A it still doesn't break but print null. The problem might be that you initialize aPtr to a different class than A, in which case you get unrecognized selector exception (you should be able to see it in the error log) and program crash.

When needing to reference an NSString later that was passed to a function in a class, what is the proper way? (iPhone dev)

In this example:
#interface something : something
{
NSString *saveString;
}
-(void)saveStringForLater:(NSString*)myString
{
//do stuff with myString
...
//then save it for later
saveString = myString;
}
-(void)someOtherTimeInFuture
{
//do stuff with saveString
...
}
So given the above, my questions are:
1) Is this safe/proper way of doing this?
2) Will I need to worry about releasing saveString?
3) Should I be copying the string instead of just saving the pointer?
Excuse my ignorance as I am fairly new to Obj-C but have a C++ and C# background.
Thanks!
This is what #properties are for. They manage getter and setter code for you, so you don't have to think about these questions.
.h
#interface MyClass : NSObject
{
NSString *myString;
}
#property (nonatomic, retain) NSString *myString;
#end
.m
#implementation MyClass
#synthesize myString;
-(void)dealloc
{
[myString release];
[super dealloc];
}
#end
With those things in place, you can now talk about self.myString and not worry about memory. When you assign to it it'll do a retain. If you assign again, it'll release the first object and retain the new one. And then it'll stick around retained until your viewcontroller unloads.
You can by all means accomplish this same end with an iVar (which is what you're doing in your code sample), but then memory management is yours to handle, and it can be a bit fiddly. Best to use the #property system to create appropriately memory-managing setter code.
You have 3 optins,
Copy - should be using if the string can change or when getting called from a code you have on control of like third party
Retain - will increase the reference count to the object and will prevent destruction of it
In both these options you have to release it when you done with it
Last you can define a property with retain,copy attribute - this will let the system worry about managing it and probably the best option in most cases

NSMutableString appendString generates a SIGABRT

This makes no sense to me. Maybe someone here can explain why this happens.
I've got an NSMutableString that I alloc at the top of my iPhone app, then append to later in the process. It results in a SIGABRT, which doesn't add up to me. Here's the code:
Header File (simplified):
#interface MyAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
NSMutableString *locationErrorMessage;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, copy) NSMutableString *locationErrorMessage;
#end
And the relevant parts of the Main:
#implementation MyAppDelegate
#synthesize window;
#synthesize locationErrorMessage;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
self.locationErrorMessage = [[NSMutableString alloc] init];
}
- (void)anotherFunction {
[self.locationErrorMessage appendString: #"Blah Blah Blah"];
}
This all seems simple enough. What am I missing?
I would call this a bug in how property setters are generated, but the answer is pretty simple:
You declared the property as (nonatomic, copy). This means that whenever the locationErrorMessage property is set, it's going to invoke copy on the new value and use that copy as the property value.
Unfortunately, invoking copy on an NSMutableString does not result in an NSMutableString, it results in an NSString (which cannot be mutated using something like appendString:).
So the simple fix would be to change the property declaration from copy to retain.
(I would say that the bug would be: If you declare a property for a mutable object as copy, then the copy setter should actually use mutableCopy and not copy) => rdar://8416047
Your property is copying the passed in string. A copy always is immutable, so you’re trying to send appendString: to an immutable NSString. Declare your property as retain and it will work or write a custom setter that copies the string using mutableCopy.
You also have a memory leak, you should use [NSMutableString string] instead of the alloc-init sequence.
Btw, you have a leak there,
self.locationErrorMessage = [[NSMutableString alloc] init];
you're copying the value, but you never release the actual first allocated NSMutableString.