Xcode ignores some of my lines - iphone

I have a part in my code that calls a method on a different class.
The different class is a singleton.
I didn't have any issues with this class until today, everything worked properly. I don't know why, but after a few insignificant changes i've made today, the code seems to ignore some of my code. It seems that everything is ok and it passes through all the lines but if i put a breakpoint inside one of the methods in my singleton class, it doesn't stop. It just doesn't call those methods.
Does anyone has an idea why could that be?
I tried cleaning the project, tried quitting Xcode, nothing helped so far.
This is an example of how my method in my singleton ".m" looks like:
-(void)setUserCurrentLocationWithLatitude:(NSNumber *)latitude andLongitude:(NSNumber *)longitude andUserIndex:(NSNumber *)userIndex{
NSMutableArray* tempPlayersArray = [NSMutableArray arrayWithArray: [[NSUserDefaults standardUserDefaults] arrayForKey: #"kgpsUsersArray"]];
NSMutableDictionary * userTempDict = [[NSMutableDictionary alloc] initWithDictionary:[tempPlayersArray objectAtIndex:[userIndex integerValue]]];
NSLog(#"latitude = %f",[latitude floatValue]);
[userTempDict setObject:latitude forKey:#"latitude"];
[userTempDict setObject:longitude forKey:#"longitude"];
[defaults setObject:tempPlayersArray forKey:#"kgpsUsersArray"];
[defaults synchronize];
}
And this is how it is defined in ".h" file:
-(void)setUserCurrentLocationWithLatitude:(NSNumber *)latitude andLongitude:(NSNumber *)longitude andUserIndex:(NSNumber *)userIndex;
And in my viewController.m file the singleton is being called initialized like this:
#import "PlayersData.h"
usersData = [PlayersData sharedInstance];
and the method is called like this:
[usersData setUserCurrentLocationWithLatitude:[NSNumber numberWithFloat:32.125493] andLongitude:[NSNumber numberWithFloat:34.858962] andUserIndex:[NSNumber numberWithInt:j]];
Thanks,

It is possible that the singelton was not created. Debug it, to be sure it is not nil.

Related

Set a new value to a NSString variable with a previous value

I'm developing an iOS application with latest SDK and XCode.
This is a simple question but I don't know how to do it because I don't want any memory leaks on my code.
I'm using ARC on my project and I have the following header declaration:
#interface UserPreferences : NSObject
{
NSUserDefaults* prefs;
}
#property (nonatomic, readonly) NSString* appLanguage;
// More code
- (void) setAppLanguage:(NSString *)appLanguage;
// More code
#end
And this is how I've implemented - (void) setAppLanguage:(NSString *)appLanguage;.
- (void) setAppLanguage:(NSString *)newAppLanguage
{
[prefs setObject:appLanguage forKey:APP_LANGUAGE_KEY];
appLanguage = [NSString stringWithString:newAppLanguage];
}
Is appLanguage = [NSString stringWithString:newAppLanguage]; correct?
I don't know it appLanguage will have a value when I set a new one to it.
Is my code correct?
Your code doesn't have any leaks; ARC automatically releases the previous value for appLanguage for you. I would write appLanguage = [newAppLanguage copy] rather than using stringWithString:, but the effect is the same.
Unless you've omitted some code, this won't work...
You've created an instance variable for NSUserDefaults, but have never instantiated it with a value. When you call [prefs setObject:appLanguage forKey:APP_LANGUAGE_KEY]; prefs will be nil.
At some point, before you use prefs, you need to do something like: prefs = [NSUserDefaults standardUserDefaults];
If you have instantiated prefs somewhere else, you'll still have an issue with this logic. Presumably, you're trying to change the NSUserDefaults to the new language passed in. In that case, the method should be:
- (void) setAppLanguage:(NSString *)newAppLanguage {
_appLanguage = newAppLanguage; // implicit synchronize will set the ivar as _appLanguage
[prefs setObject:newAppLanguage forKey:APP_LANGUAGE_KEY];
[prefs synchronize];
}
Since the _appLanguage instance variable is set to strong by default, ARC will automatically add the necessary release and retain code, preventing a memory leak.
Also, if you are trying to create a private setter method, take - (void) setAppLanguage:(NSString *)appLanguage; out of the interface. If you're not trying to make a private setter, remove readonly from the property declaration.

Saving multiple map annotations - crashes

I have been searching top and bottom for info on how to do this. I landed on a great tutorial! So I am still quite newbie to this. Basically I have been trying to store Map View annotations to an array. The annotations are a separate class which basically overrides / acts as a MKAnnotation for a pin annotation. It has three properties:
Annotation Coordinate
Annotation Title
Annotation Subtitle
This array needs to store into the NSUserDefaults. I faced a problem, here is the log:
[UIMutableIndexPath setObject:forKey:]: unrecognized selector sent to
instance 0x1187b0
My Annotation class objects stored inside the array could not be saved to the user defaults. So I had to turn this array into NSData and then save it, right?
I have a lot of code setup, just not working. Here is how I attempt all of this:
View Controller Class.m:
- (void)syncMap { // this method is called in viewWillDissapear (for running tests) and applicationDidEnterBackground in App Delegate
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject: localOverlays]; // this is the array I was talking about
[defaults setObject:data forKey:#"overlays"];
[defaults synchronize];
}
- (void)initCircles { // called in AppDelegate UIApplicationDelegate method: applicationDidFinishLaunchingWithOptions
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey: #"overlays"];
localOverlays = [NSKeyedUnarchiver unarchiveObjectWithData: data];
if (!localOverlays) {
// Either there is a problem or it is the first time opening the app
localOverlays = [[NSMutableArray alloc] init];
}
}
NOTE: I AM TESTING WITH TWO ANNOTATIONS IN THE ARRAY (localOverlays)
So, my localOverlays can be encoded / archived(using NSCoder) since it is an NSArray. However, I had to add some further setup in my Annotation class. In its .h it uses to NSCoding and MKAnnotation: like the following< NSCoding, MKAnnotation>. Sorry if I am not using the correct term. Here is my .m:
- (void)encodeWithCoder:(NSCoder *)aCoder { // should only be called when app enters background state, but since that cannot log in the console, like before I set it up so it should also be called in viewWillDissapear
NSLog(#"encodeCoder called in Annotation"); // gets called twice when the view will disappear... GOOD!
[aCoder encodeObject: title forKey: #"title"];
[aCoder encodeObject: subtitle forKey: #"subtitle"];
[aCoder encodeDouble: coordinate.latitude forKey: #"latitude"];
[aCoder encodeDouble: coordinate.longitude forKey: #"longitude"];
}
- (id)initWithCoder:(NSCoder *)aDecoder { // Should be called only at startup of app (not the first time you startup the app though... because data will be NULL)
NSLog(#"In the Annotation class, initWithCoder is called"); // Does get called at appropriate times twice... NICE!
self = [super init];
if (self) {
title = [aDecoder decodeObjectForKey: #"title"];
subtitle = [aDecoder decodeObjectForKey: #"subtitle"];
double lat = [aDecoder decodeDoubleForKey: #"latitude"];
double lon = [aDecoder decodeDoubleForKey: #"longitude"];
coordinate = CLLocationCoordinate2DMake(lat, lon);
}
return self;
}
So as you can see, I have everything setup for archiving, right? Well it seems not... because now in the .m of the ViewController, I also have this code in viewDidLoad:
for (Annotation *pin in localOverlays) {
if (pin) {
NSLog(#"valid pin: _CMD updateCircles");
[mapView addAnnotation: pin];
}
}
This code works nicely and fine the first time I open my app and add the pins. Okay, so now I have exited the view and quit the app, and deleted from multitasking bar. When I open it back up, I get a crash at the fast enumeration line:
-[NSURL countByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance 0xcd31140
So, there is something wrong with all my archiving and encoding setup. What is wrong here... I know this was a lengthy question but I tried to structure it well. Am I setting up my code totally incorrect, is there a typo/bug in my code. Thanks all!
UPDATE:
I have got the coordinate variable encoded, therefore when I startup the app after the pin appear at the right coordinate, but when I try to press it to see the title and subtitle, I get the following crash:
objc_msgSend
So something is released right... just a guess... bad memory management? What would cause this crash in my code?
UPDATE:
I have looked deeper and further into my code and changed a few release statements around, just improved my memory management and done a bit of optimization. Now I get a more specific crash:
*** -[CFString length]: message sent to deallocated instance 0x147490
So my title or subtitle IS deallocated... why? I have checked my code it should be absolutely fine, especially since the coordinates are fine...
UPDATE:
I have solved this problem! I came to the realization, the coordinate two variables, latitude and longitude are doubles, data types... NOT objects! Therefore they are sticking on and working only BECAUSE they are copied... unlike objects which are references. Long story short I needed to retain. Just like this:
title = [[aDecoder decodeObjectForKey: #"titler"] retain];
subtitle = [[aDecoder decodeObjectForKey: #"subtitler"] retain];
I'm not sure what exactly is the reason for the crashes. But I noticed some mistakes in your encode/decode methods:
EDIT: Only if your super class conforms to NSCoding:
In encodeWithCoder you should at first call:
[super encodeWithCoder: aCoder];
In initWithCoder replace
self = [super init];
by
self = [super initWithCoder:aDecoder]
The following returns an immutable object (not NSMutableArray):
localOverlays = [NSKeyedUnarchiver unarchiveObjectWithData: data];
Replace this line by:
localOverlays = [[NSKeyedUnarchiver unarchiveObjectWithData: data] mutableCopy];
I hope that helps!
I have solved this problem! I came to the realization, the coordinate two variables, latitude and longitude are doubles, data types... NOT objects! Therefore they are sticking on and working only BECAUSE they are copied... unlike objects which are references. Long story short I needed to retain. Just like this:
title = [[aDecoder decodeObjectForKey: #"titler"] retain];
subtitle = [[aDecoder decodeObjectForKey: #"subtitler"] retain];

Accessing NSDictionary problem

I'm only new to iPhone development, so my apologies if this is a silly question. I'm building various apps based on a book I'm reading and one of their suggestion was to build a mini web browser. I thought this would be easy, but while most of it is, I'm seriously struggling with the NSDictionary.
I have a UISegmentedControl used to display various bookmarks. The bookmark name that is displayed on the buttons of the UISegmentedControl is going to be my key and the url is the value associated with it.
I first try to declare an NSDictonary as a private (global variable), but since I could not get it to work, I resorted to declare it in my header file as follows:
#property (nonatomic, retain) NSDictionary *bookmarks;
I synthesize it and I initialized it in the viewDidLoad as follows:
- (void)viewDidLoad
{
bookmarks = [NSDictionary
dictionaryWithObjectsAndKeys:#"http://www.microsoft.com",
#"Microsoft",
#"http://www.google.com",
#"Google",
#"http://www.apple.com",
#"Apple",
#"http://msdn.microsoft.com",
#"MSDN", nil];
[super viewDidLoad];
}
I then associated a control with my segmented control and when the event is triggered and the function is called I've got the following code which is called:
- (IBAction) getShortcut:(id)sender
{
NSString *shortcut;
shortcut = [shortcuts titleForSegmentAtIndex:shortcuts.selectedSegmentIndex];
NSString *url = [bookmarks valueForKey:shortcut];
//[self navigateTo: url];
[url release];
}
When a button from the UISegmentedControl is clicked, I extract the value and stored it into shortcut and then I try to use the shortcut variable as a key to extract the associated value from the NSDictionary "bookmarks" but it keeps crashing on NSString *url = [bookmarks valueForKey:shortcut];
and bombs out of my function and displays the usual error EXC_BAD_ACCESS
Any help would be greatly appreciated.
T.
You have two options. one is to deal with the ivar directly as #Matt S. posted. Note that in this case you need to keep you object with enough retain count. You're using and auto released object and causing the error.
The other option is to use the property you already defined:
self.bookmarks = [[NSDictionary ...]];
And the property retains it.
That dictionary is autoreleased.
Try this:
self.bookmarks = [NSDictionary dictionaryWithObjectsAndKeys...]
You didn't retain the NSDictionary.
Do:
bookmarks = [[NSDictionary
dictionaryWithObjectsAndKeys:#"http://www.microsoft.com",
#"Microsoft", nil] retain];
The problem is, that you do not retain "bookmarks" in the viewDidLoad method. There is an naming convention mentioned somewhere in the Apple docs: If an intialisation method starts with "init..." the returned object is retained, if not you have to do it yourself. The "dictionaryWithObjectsAndKeys" returns and object with retain count 0, which means, that after the scope of assignment (your viewDidLoad method) it is immediatly released again.
So just put a
[bookmarks retain];
after your initalisation and you are done. Another solution which does the retaining for you
bookmarks = [[NSDictionary alloc] initWithObjectsAndKeys ...];
And you shouldn't release the url in your action. It gets released, once you release the dictionary

Can't set member variable twice (NSManagedObject)

I am getting the EXC_BAD_ACCESS error when trying to set a value inside a subclass of NSManagedObject for the second time.
I am using zombies but nothing is showing up in the console. Printing out the object using GDB I see that the object has the same memory address both times I try to set the value - not sure why though.
Situation:
I have a view (A) that, when a QR code is scanned, adds a subview (B) which in turn downloads XML that is then saved into a subclassed NSManagedObject.
Inside the subview (B) I navigate back (removeFromSuperView is called)
Back in the original view (A)
Next time, when the same QR code is scanned, it (A) finds the NSManagedObject from the database and attaches that to an instance variable on a new view (same type as B) that it then adds as a subview to the original (A).
In view B's viewDidLoad i always try to set the current date in order to track when a user "saw" that object. This is where I get the EXC_BAD_ACCESS error:
self.currentPiece.piece_last_viewed = [[NSNumber alloc] initWithDouble:[[NSDate date] timeIntervalSince1970]];
Where self.currentPiece is the instance of a subclassed NSManagedObject that was attached in A when that object existed in the database.
I know that it is being released somewhere but I don't know where since managed objects take care of much of that on their own. The error only occurs the second time around that I try to set the value.
I have tried to make this clear. Please tell me if you want me to clarify it even more.
Thanks for the help (have worked on this for some hours now)
UPDATE:
Declaring the piece_last_viewed in HubPiece.h:
#interface HubPiece : NSManagedObject {
}
// ...
#property (nonatomic, retain) NSNumber *piece_last_viewed;
HubPiece.m:
#dynamic piece_last_viewed;
//...inside init method:
self.piece_last_viewed = [[NSNumber alloc] initWithDouble:[[NSDate date] timeIntervalSince1970]];
UPDATE 2:
It is not due to the switching of subviews, that is ruled out. I then realized that I didn't save my changes either, so I introduced save: inside the subclassed NSManagedObject. I then got an earlier error the first time I try to save the entity instance (which saved during an app session, but the data vanishes if I quit the app entirely and then open it up again). So I thought using [context save:&error] would be a good idea :) ...but now that doesn't work and give me a EXC_BAD_ACCESS error.
The HubPiece itself is initialized from another class HubPieceView.m :
self.currentPiece = [[HubPiece alloc] initWithXML:pieceXML];
self.currentPiece is a class variable of type HubPiece and it first declared in .h file and then synthesized in .m file.
Then inside HubPiece.m the initializer looks like this:
-(id)initWithXML:(TBXMLElement *)pieceXML
{
// Setup the environment for dealing with Core Data and managed objects
HenryHubAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSEntityDescription *entityHubPiece = [NSEntityDescription entityForName:#"HubPiece"
inManagedObjectContext:context];
// STORING values
self = [[HubPiece alloc] initWithEntity:entityHubPiece insertIntoManagedObjectContext:context];
// ...setting variables with normal assignment: self.var = value;
NSError *error;
// Save fails
if (![context save:&error] ){
NSLog(#" ERROR: %#", [error localizedDescription]);
}
return self;
}
I just realized my problem. I had been assigning values to the entity through with normal '=' assignment:
self.currentPiece.piece_last_viewed = [[NSNumber alloc] initWithDouble:[[NSDate date] timeIntervalSince1970]];
When it should have been done:
[self setCurrentPiece.piece_last_viewed:[[NSNumber alloc] initWithDouble:[[NSDate date] timeIntervalSince1970]] ];
This is because it is a managed object which creates it's own accessors at runtime through the #dynamic compiler instruction.

NSMutableArray gets corrupted

I'm doing an iPhone application which uses a navigation control to browse through some data. This data is stored in a sqlite database and I have a class which gets it and returns it in a NSMutableArray of NSStrings.
The problem is that in the first screen of the navigation everything works prefectly, but in the second screen (another view which is pushed) the same code fails because the NSMutableArray gets corrupted. In the debugger I can see that it is returned correctly, but when it's time to use it the pointers have become corrupted and the application crashes.
I have put breakpoints in all my functions, and I can't see anywhere where it can get corrupted. And as the first view, which uses the same exact code, even accesing the same eact tables, works correctly I don't really know where to look.
If anyone want to have a look at the code I have uploaded it to my site: http://sachafuentes.com/iBacus.zip
Thanks in advance.
UPDATE:
The problem lies in the function where I get the data, which looks like (this is a simplified version with some pseudo-code).
-(NSMutableArray *) getPaises {
NSMutableArray * paises;
paises = [[NSMutableArray alloc] init];
while( get new row ) {
NSString *aPais = get the value;
[paises addObject:aPais];
[aPais release];
}
return paises;
}
If I comment out [aPais release] everything works, but to me this looks like a memory leak, as the NSString won't be released.
Okay, here's the problem:
NSString *aPais = [NSString stringWithUTF8String:(char*)sqlite3_column_text(compiledStatement, 0)];
By convention, any time that you see an alloc and an init, you need a release somewhere down the road.
By convention, any time that you use an xWithX: style method, the resulting object will be released for you.
Therefore, this statement:
[aPais release];
will cause your method to crash, as the object is released before it should be. Just remove this line, set your NSMutableArray instance to be autorelease-d and you should get better results.
Look for wrong memory management, that's the likeliest cause for crashes. I think you release your objects somewhere where you shouldn't and therefore you have dangling pointers in the array.
Update1
[aPais release] is wrong, as you don't retain it anywhere in this method. Returned values should always be autoreleased. You should have the same amount of retain as release in your code.
(Some people argue that a retain can also be an alloc init, but I always try to use alloc init autorelease, but this is a matter of style.)
BTW
You should autorelease your array, you're only retaining it here with [[alloc] init].
Any object that you alloc and init must be release-d when you're finished with it, or you will have a memory leak.
Since you are passing the reference outside the scope of the getPaises method, you must autorelease the NSMutableArray, or you will have a memory leak:
paises = [[[NSMutableArray alloc] init] autorelease];
Can you please clarify the step here:
NSString *aPais = get the value;
It's not clear what happens in "get the value" and I suspect this is one cause of instability.
I see that the code is (verbatim)
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
NSString *aPais = [NSString stringWithUTF8String:
(char*)sqlite3_column_text(compiledStatement, 0)];
[paises addObject:aPais];
[aPais release];
}
...and it's exactly as #gs puts it. aPais is autoreleased and should not be released.
You can also use a convenience constructor to initialize the NSMutableArray:
NSMutableArray *paises = [NSMutableArray array];
This is equivalent to doing:
NSMutableArray *paises = [[[NSMutableArray alloc] init] autorelease];