iPhone app quits randomly when accessing a NSString - iphone

I've got a problem with a NSString in my app.
I've defined it in the header file of my view controller.
NSString *locationCoordinates;
and I set its value in a -(void) method.
- (void)locationUpdate:(CLLocation *)location {
<...>
NSArray *locArray = [locString componentsSeparatedByString:#", "];
NSString *xCoordinate = [locArray objectAtIndex:0];
NSString *yCoordinate = [locArray objectAtIndex:1];
locationCoordinates = [NSString stringWithFormat:#"%#,%#", xCoordinate, yCoordinate];
}
In this method, I can print it to the console with
NSLog(locationCoordinates);
But if I want to view it in the console in another method, my app instantly quits.
- (IBAction)saveAndReturnToRootView {
NSLog(locationCoordinates);
}
The console tells me:
2010-02-24 14:45:05.399 MyApp[73365:207] *** -[NSCFSet length]: unrecognized selector sent to instance 0x4c36490
2010-02-24 14:45:05.400 MyApp[73365:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSCFSet length]: unrecognized selector sent to instance 0x4c36490'
2010-02-24 14:45:05.401 MyApp[73365:207] Stack: (
32887899,
2434934025,
33269819,
32839286,
32691906,
32417461,
32527181,
32527085,
32747749,
356942,
630491,
63461,
2868313,
4782069,
2868313,
3275682,
3284419,
3279631,
2973235,
2881564,
2908341,
40984273,
32672640,
32668744,
40978317,
40978514,
2912259,
9744,
9598
)
How can I solve this problem?
Thanks in advance ;-)

You arent retaining the String, so the memory is being cleared up. This causes the crash when you try to access it.
To retain it, you can add the following line
[locationCoordinates retain];
Remember to release it when you no longer need it - probably in the destructor of your class, or else you will have a memory leak.
It is standard practice in Objective C to use properties for such class members. In the header file use
#property (nonatomic, retain) NSString *locationCoordinates;
Then in the implementation chuck in a
#synthesize locationCoordinates;
When you access locationCoordinates access it through self as :
self.locationCoordinates = [NSString stringWithFormat:#"%#,%#", xCoordinate, yCoordinate];
Objective C will create a getter and setter property that will handle the retain for you in the most efficient manner.
Incidentally, the nonatomic keyword in the property tells objective c that you dont need it to create any thread synchronization around the property access. If you are going to be multithreading the class, you should consider removing nonatomic. This will then ensure the property access is thread safe.
No point doing any work that you can get the compiler to do for you!

You should retain the string when storing it in a variable of your class:
locationCoordinates = [NSString stringWithFormat:#"%#,%#", xCoordinate, yCoordinate];
[locationCoordinates retain];
The reason is that [NSString stringWithFormat:...] returns an autoreleased instance. The string will be automatically released when the function ends.
You could also copy the string:
locationCoordinates =
[[NSString stringWithFormat:#"%#,%#", xCoordinate, yCoordinate] copy];
And of course, don't forget to release it again in dealloc:
- (void) dealloc {
[locationCoordinates release];
[super dealloc];
}

Related

Error in accessing global declared NSArray values in class methods

I have problem in fetching the element from array,
I have declared NSArray *array globally, also tried through myfile.h file property, but I'm not able to access array element in my view controller setCode method.
NSArray *array;
//this is global array also i tried in my.h file
//#property(nonatomic, retain) NSArra *array;
//and by accessing it #synthesize array; also not works for me.
-(void)viewDidLoad
{
array = [NSArray arrayWithObjects:#"sssss", #"hjjjjj", #"kkkkkk"];
[self setCode];
}
-(void)setCode
{
NSString *code = [array objectAtIndex:0];
NSLog(#"code %#",code);
}
#end
It throwing some errors:
2013-08-05 16:25:28.429 test_project_ios_31st_july[2409:c07] -[__NSMallocBlock__ objectAtIndex:]: unrecognized selector sent to instance 0x9c82350
2013-08-05 16:25:28.430 test_project_ios_31st_july[2409:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSMallocBlock__ objectAtIndex:]: unrecognized selector sent to instance 0x9c82350'
*** First throw call stack:
(0x23fb012 0x1c98e7e 0x24864bd 0x23eabbc 0x23ea94e 0x283f 0x17594f9 0x24550c5 0x23afefa 0x168dbb2 0x16a0e6b 0xdb9f 0x16d2417 0x16ebb24 0x16a0d60 0x174da8a 0x43ac2 0x16d2417 0x16ebb24 0x16a0d60 0x174da8a 0x464d5 0x17594f9 0x24550c5 0x23afefa 0x16a0a0c 0xa3d0e6 0x206353f 0x2075014 0x20657d5 0x23a1af5 0x23a0f44 0x23a0e1b 0x2ad87e3 0x2ad8668 0xbdcffc 0x2192 0x20c5)
libc++abi.dylib: terminate called throwing an exception
Please try following code:
NSArray *array;
-(void)viewDidLoad
{
array = [NSArray arrayWithObjects:#"sssss", #"hjjjjj", #"kkkkkk"];
[array retain];
[self setCode];
}
-(void)setCode
{
NSString *code = [array objectAtIndex:0];
NSLog(#"code %#",code);
[array release];
}
#end
You are declaring another object from the array inside your viewDidLoad, so your global array object will never get allocated, you need to remove the declaration as below:
-(void)viewDidLoad
{
array = [NSArray arrayWithObjects:#"sssss", #"hjjjjj", #"kkkkkk"];
int i;
[self setCode];
}
And by the way the setCode doesn't do anything rather than printing!, you can change its name to printCode.
Add
#interface PeopelListViewController : UIViewController
{
NSArray *array;
}
//in my.h file
//#property(nonatomic, retain) NSArra *array;
//and #synthesize array;
just you need to Put nil at the end of your NSArray.
such like
self.array = [NSArray arrayWithObjects:#"sssss", #"hjjjjj", #"kkkkkk", nil];
first you declare an array in implementation (.m file) like this
#implementation : myviewcontroller {
NSArray *array;
}
then initialize it like
array = [NSArray arrayWithObjects:#"sssss", #"hjjjjj", #"kkkkkk", nil];
it must work
What you did is to create a reference - local, here in this method.
-(void)viewDidLoad
But in your -(void)setCode method, you are accessing your global variable .
The global variable is not yet allocated a memory, neither initialized hence the error.
So you need to understand the scope of variables. Local scope preceeds global scope. Anyways you are working with two different array objects.
Change this in your viewDidload implementation to make it work:
// No NSArray at front that will make it an another array object
array = [NSArray arrayWithObjects:#"sssss", #"hjjjjj", #"kkkkkk"];

How do I removeAllObjects on my NSMutableArray that is part of another object?

I have an object defined like this:
Scores.h:
#interface Scores : NSObject {
NSString *sentenceKey;
NSMutableArray *scorrectAnswers;
}
#property (nonatomic, copy) NSString *sentenceKey;
#property (nonatomic, copy) NSMutableArray *scorrectAnswers;
+ (id)addScore:(NSString *)senKey;
- (id)initWithSentenceKey:(NSString *)sKey
scorrectAnswers:(NSMutableArray *)scorrectAs;
- (id)initWithSentenceKey:(NSString *)sKey;
- (void)removeArrayObjects;
Score.m:
#import "Scores.h"
#implementation Scores
#synthesize sentenceKey, scorrectAnswers;
+ (id)addScore:(NSString *)senKey
{
Scores *newScore = [[self alloc] initWithSentenceKey:senKey
scorrectAnswers:[NSMutableArray new]];
return [newScore autorelease];}
I'm trying to removeAllObjects on my mutable array with this method:
- (void)removeArrayObjects;{
[scorrectAnswers removeAllObjects];}
...which I call from another program like this:
for (Scores *sScore in scores)
{
[sScore removeArrayObjects];
}
... and I get this error when I run it:
-[__NSArrayI removeAllObjects]: unrecognized selector sent to instance 0x53412d0
Can anyone tell me what I'm doing wrong here? Thanks.
You are not dealing with an NSMutableArray as the error indicates you have an immutable NSArray.
This question may be your answer NSMutableArray addObject: -[__NSArrayI addObject:]: unrecognized selector sent to instance
Basically the copy you used when defining your #property will cause the setter to be generated using
scorrectAnswers = [newMutableArray copy];
which returns an immutable NSArray.
You can re-implement this method and change the previous line for:
scorrectAnswers = [newMutableArray mutableCopy];
or use retain instead of copy
This can also occur when getting data from a plist
If you are using a plist it will return an NSArray even if you save an NSMutableArray it will be cast. So when retrieving you will need to do something like:
scorrectAnswers = [[NSMutableArray alloc] initWithArray:[userDefault objectForKey:#"my_array_key"]]
It doesn't look like like the memory pointed to by scorrectAnswers is actually pointing to an NSMutableArray. Where and how do you initialize that variable? If you are setting the ivar directly with an autoreleased object, like:
scorrectAnswers = [NSMutableArray arrayWithCapacity:10];
then the autoreleased array will be destroyed, since you're not retaining it (or copying it). If that memory gets reallocated to point to another object, you'll see an error like the one you're getting, with an unexpected type. If the memory has not been reallocated, you'll get an EXC_BAD_ACCESS error.
Similar to what was mentioned above, I had an NSMutableArray which was being re-allocated somewhere in my code as an NSArray. Once I modified that to correctly be an NSMutableArray, it resolved my problem.
I would suggest doing a quick search to ensure that you have not reallocated the array somewhere in your project and modify accordingly.

instruments showing NSPlaceholderstring leaks

I'm trying to reduce the memory leaks in my app, so i used instruments to find all the leaks. I managed to remove almost all of the leaks, except a very annoying one.
Instruments is telling me that i have a lot of NSPlaceholderstring leaks.
The code that generated the leak (according to instruments) is:
if (nil == storedHash)
{
NSString *description = [[NSString alloc] initWithFormat:#"1 = %# 2= %d", uId, service];
self.storedHash = description; // This line is the leak according to instruments
[description release];
description = nil;
}
return storedHash
storedHash is define like this:
#property(copy) NSString* storedHash;
I tried everything i can think of:
I used retain instead of copy
I used an autorelease allocation of the NSString (stringWithFormat)
I tried wrapping the code with an autorelease pool
Nothing of the above changed the leak. (In some cases the type of the leaks change, but there are still leaks)
Ideas anyone?
Where do you release storedHash? Do you release it in dealloc?
Note that NSPlaceholdeString is an implementation detail; it is the class of the instance returned by NSString's +alloc method.
How about in the dealloc method? Did you release the storedHash in the dealloc method? And how about checking if (nil == self.storedHash)
You should use
#property(nonatomic, retain) NSString* storedHash;
instead copy. #property(copy) didn't release your old NSObject and you should do it yourself:
if (nil == storedHash)
{
NSString *description = [[NSString alloc] initWithFormat:#"1 = %# 2= %d", uId, service];
[self.storedHash release];
self.storedHash = description; // This line is the leak according to instruments
[description release];
// description = nil; // it's unnecessary
}
also you should release storedHash in dealloc.

iPhone +NSCoding/NSKeyedArchiver

I Have a small problem with NSCoding and NSKeyedArchiver when persisting my App Settings class and was hoping someone could spot an issue if it's my code, I am relatively new to Obj-C but have plenty of coding experience in numerous languages so the code seems ok to me but...
I have an instance class to hold my app Settings, the class itself is a retained property of the main App Delegate, this is created via a
#interface AppDelegate : NSObject <UIApplicationDelegate> {
Settings *settings;
[...]
}
#property (nonatomic, retain) Settings *settings;
[...]
This is created in the applicationDidFinishLaunching event as:
settings = [Settings LoadSettings];
If I comment out the above line then the app works fine every time, however if I pull the oject back from persisted settings using NSCoder and NSKeyedUnarchiver, the SIGARBT error is thrown as a NSCFString selector is being sent for what is encoded as a boolean property? The Settings Class is defined as an NSObject which implements the protocol.
#interface Settings : NSObject <NSCoding>
As I say, creating an instance of the settings class is fine, there is no issue, saving it seems OK as well as checking the returning class from the LoadSettings method shows the right values, only after exiting the method does the expected bool value seem to be getting sent to the load method as an NSCFString
- (id)initWithCoder:(NSCoder *)decoder {
if (self = [super init]) {
[...]
self.animateMenus = [decoder decodeBoolForKey:#"animateMenus"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[...]
[encoder encodeBool:animateMenus forKey:#"animateMenus"];
}
Once the settings have been loaded the property in question is used like this:
SettingsViewController *settingsView = [[SettingsViewController alloc] initWithNibName:#"SettingsView" bundle:nil];
[self presentModalViewController:settingsView animated:[AppDelegate instance].settings.animateMenus];
[settingsView release];
**The animateMenus member of the settings class will now throw the following:
-[NSCFString animateMenus]: unrecognized selector sent to instance 0xc712570 2010-10-15 11:12:51.828 App[900:207] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSCFString animateMenus]: unrecognized selector sent to instance 0xc712570'
Whereas, taking the 'settings = [Settings LoadSettings];' call out of the app start-up removes the issue (but then always uses the app defaults)?
Load and Save Methods:
+ (Settings*) LoadSettings {
Settings *s = nil;
#try {
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:#"settings"];
if (data == nil) {
s = [[Settings alloc] init];
[s Initialise];
[s SaveSettings];
}
else
s = (Settings*)[NSKeyedUnarchiver unarchiveObjectWithData:data];
}
#catch (NSException * e) {
NSLog(#"Error Loading Settings\n%#", [e reason]);
}
#finally {
return s;
}
}
// Saves the settings dictionary to the user's device documents folder..
- (void) SaveSettings {
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:#"settings"];
}
Load is a static method all other members of Settings are instance.
You need to do:
settings = [[Settings LoadSettings] retain];
That's because in your LoadSettings, the result of NSKeyedUnarchiver is an autoreleased object. And it got released :-) At that location a new object was created, an NSString in this case.
Edit:
Well, I just noticed a major problem with LoadSettings that I missed at first: you mix memory release strategies: in one codepath you return the result of [[Settings alloc] init] which is not autoreleased, while in the other you retain the result of NSKeyedArchiver which is autoreleased. You need to make sure only one concept is used.
Since the method name LoadSettings does not contain alloc, copy or new in its name the convention is that it should return an autoreleased object. Thus, you should do:
if (data == nil) {
s = [[Settings alloc] init];
[s Initialise];
[s SaveSettings];
[s autorelease];
}
else
...

I-Phone: Trying to check an Array for an item based on a string produced

I'm writing a program that will concatenate a string based on letters, and then check an array to see if that string exists. If it does, then it will print a line in IB saying so.
I've got all the ins-and-outs worked out, save for the fact that the simulator keeps crashing on me!
Here's the code:
-(IBAction)checkWord:(id)sender
{
NSMutableArray *wordList = [NSMutableArray arrayWithObjects:#"BIKE", #"BUS", #"BILL", nil];
if([wordList containsObject:theWord])
{
NSString *dummyText = [[NSString alloc] initWithFormat:#"%# is a real word.", theWord];
checkText.text = dummyText;
[dummyText release];
}
}
"theWord" is the string that is being referenced against the Array to see if it matches an item contained within it. In this case "BIKE" is 'theWord'.
Thank you for your help in advance!
-MB
The variable "checkText" is a UILabel that is being linked 'dummyText'. It is defined as retain,nonatomic.
-(IBAction)checkWord:(id)sender
{
NSArray *wordList = [[NSArray alloc] initWithObjects: #"BIKE", #"BUS", #"BILL", nil];
if([wordList containsObject: theWord])
{
NSString *dummyText = [[NSString alloc] initWithFormat:#"%# is a real word.", theWord];
checkText.text = dummyText;
[dummyText release];
}
else{
NSString *dummyText = [[NSString alloc] initWithFormat:#"%# is not a real word.", theWord];
checkText.text = dummyText;
NSLog(#"NOT A WORD");
[dummyText release];
}
[wordList release];
}
I'm wondering if the containsObject is supposed to be a BOOL statement? If so, how would I phrase it?
Here is how checkText and theWord are defined in the header file for the project.
#interface blah blah {
IBOutlet UILabel *checkText;
NSString *theWord;
}
#property (retain, nonatomic) UILabel *checkText;
#property (retain, nonatomic) NSString *theWord;
#end
This isn't the whole file, just a demonstration of how the variables are defined.
Here's what the console says:
2010-03-20 21:01:42.822 Button_fun[5563:207] *** -[__NSPlaceholderArray arrayWithObjects:]: unrecognized selector sent to instance 0x3906450
2010-03-20 21:01:42.823 Button_fun[5563:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderArray arrayWithObjects:]: unrecognized selector sent to instance 0x3906450'
2010-03-20 21:01:42.823 Button_fun[5563:207] Stack: (
29295707,
2547500297,
29677627,
29247094,
29099714,
12827,
2724869,
3132238,
3140975,
3136187,
2829791,
2738120,
2764897,
37391705,
29080448,
29076552,
37385749,
37385946,
2768815,
10484,
10338
)
And yes, the application automatically quits when the "Check Word" button is pressed.
How have you defined your checkText property? As an NSString property, is it set to copy, and not retain?
P.S. Don't create answers to your own question to add in more information. Edit your original question instead.