This may sound a newbie question however I'm new iOS dev,
recently I've switched to ARC and have got following issue in my code. I've implemented a class with following init method
- (id)init
{
self = [super init];
if (self) {
TokenManager* tokenManager = [[TokenManager alloc] initWithApikey:<my valid token>];
mRequest = [[GeoCodingRequest alloc] initWithApikey:apiKey withOptions:nil tokenManager:tokenManager];
mRequest.delegate = self;
}
return self;
}
where mRequest in interface is declared like this __strong GeoCodingRequest* mRequest;
In my other method of the same class I send a message to mRequest like this
[mRequest findObject:<some valid array> around:<some valid location> withDistance:<some valid radius>];
When the message is sent to object app crashes with following message
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString appendRequestWithToken:]: unrecognized selector sent to instance 0x8974640'
findObject: around: withDistance: - is a method from public library, so I've not access to its implementation.
Please help me to understand why this crash happens ?!
I guess it is coming from ARC _strong/_weak qualifier usage or smth.
The message means that mRequest has been deallocated has that a string is now using the memory that had previously been allocated for mRequest.
You should run your app with Zombies enabled to understand when mRequest gets deallocated.
It looks like the tokenManager isn't retained by the request (which is a bug in the library). As it isn't retained anywhere, the tokenManager is deallocated and a new object (here an instance of NSString) may be allocated at the same place.
You need to store the tokenManager in a strong instance variable (just as mRequest) in order to retain it as long as the request needs it.
if you have any weak references try to use
MyObject * strongMyObject = weakMyObject;
if(strongMyObject){
NSLog(#"This is not released");
}
It's a good practice when you have weak references. Try this.
Related
When I run my application, which does not use ARC, in the xcode 4.5.1 (LLDB) debugger with zombies enabled, I get this error twice (2) when calling -[super dealloc] (-[NSObject dealloc]):
* -[V2APIClient class]: message sent to deallocated instance 0x9d865c0
* -[V2APIClient class]: message sent to deallocated instance 0x9d865c0
When I run the same application in the xcode 4.4.1 (LLDB) debugger, I get the error message once (1).
When I run a slightly earlier version of the same application in XCode 4.3.2, I don't get the error message at all (0). I will retry this with the same/newest code.
FYI - This appears to be exactly the same problem as this other post, which has not yet been answered:
-[Foo class]: message sent to deallocated instance on [super dealloc])
I attempted to avoid reposting the same question twice, but I was advised to proceed:
https://meta.stackexchange.com/questions/152226/avoiding-asking-a-question-thats-already-been-asked
Also, I also just asked the equivalent question in the Apple Developer Forums:
https://devforums.apple.com/thread/171282
Finally, here is the essence of my class:
#interface ASIHTTPRequestHandler : NSObject {
id _error;
}
#property (nonatomic,retain) id error;
#end
#implementation ASIHTTPRequestHandler
#synthesize error = _error;
-(id)init
{
self = [super init];
if (self)
{
self.error = nil;
}
return self;
}
-(void)dealloc
{
self.error = nil;
[super dealloc];// this is the line that appears to cause the problems
}
#end
Please help me resolve this problem.
I don't believe I am violating any memory management rules, but this error seems to imply otherwise. I'm hesitant to check in any new code until I can resolve this problem.
Thanks,
Chuck
p.s. For the record, here is the calling code:
PanoTourMgrAppDelegate *ptmAppDlgt = [PanoTourMgrAppDelegate getApplicationDelegate];
Settings *settings = ptmAppDlgt.settings;
Identification *identification = ptmAppDlgt.identification;
V2APIClient *v2ApiClient = [[V2APIClient alloc] initWithSettings:settings identification:identification];
NSDictionary *result = [v2ApiClient get_application_status];
BOOL success = [v2ApiClient callWasSuccessful:result];
if (!success)
{
id error = v2ApiClient.error;
NSString *mbTitle = nil;
NSString *mbMessage=nil;
if ([error isKindOfClass:[NSString class]])
{
mbTitle = #"Application version no longer suppported";
mbMessage = (NSString*)error;
[MessageBox showWithTitle:mbTitle message:mbMessage];
}
}
[v2ApiClient release]; // This is the line that indirectly causes the messages above
If you are messaging a deallocated instance, it is because you haven't managed memory correctly. You have release that is not balanced by a retain; an over-release.
First, do a "build and analyze" on your code. Fix any problems identified.
Next, run under Instruments with zombie detection enabled and turn on the reference count tracking feature. Then, when it crashes, inspect all the retain/release events to the object in question. You'll find an extra release. The challenge is to stick a retain into the right spot to balance the release.
(And as Rob rightly points out, it may simply be a case of an extra call to release.)
This is a bug in the debugger in some versions of Xcode.
I've just had it in Xcode 4.4.1 but it is not in Xcode 4.6. To exercise the bug I created a new "Single View Application" project, switched on "Enable Zombie Objects" in the scheme dialog, and ran the following code in the View Controller, with a break point set on the final line.
- (void)viewDidLoad {
[super viewDidLoad];
NSObject *object = [[NSObject alloc] init];
[object release];
}
This results in the following message in the debugger:
-[NSObject class]: message sent to deallocated instance 0x6a7e330
You can also see the object in the variables section of the debugger now describes its class as _NSZombie_. If you remove the breakpoint the message is no longer shown. The call to the class method is made by the debugger after the object is correctly deallocated.
I have found some problems when saving NSManagedObjectContext inside NSOperation with turned on ARC. Without ARC everything was fine before. It is always gives EXC_BAD_ACCESS during saving. The code looks like this:
//on the main thread
-(void)someFunc
{
array = ... //fetching an array of entities from a core data
for(SomeEntity * obj in array)
{
NSSomeOperation * op = [[NSSomeOperation alloc] initWithValue:[obj someField]];
//start an operation
}
}
//NSSomeOperation implementation
//...
- (void)main {
//some code
NSError * error = nil;
[mainContext lock];
if (![mainContext save:&error]) { //<--- HERE EXC_BAD_ACCESS
//process error
}
[mainContext unlock];
//some code
}
//...
Using of [mainContext setRetainsRegisteredObjects:YES] and objectWithID don't resolve this issue.
EXC_BAD_ACCESS (code=1)
EXC_BAD_ACCESS (code=13)
-[__NSCFType contextDidSave:]: unrecognized selector sent to instance 0x7fc5c505d940
An observer of NSManagedObjectContextDidSaveNotification illegally threw an exception.
Objects saved = {
inserted = "{(\n)}";
updated = "{(\n <SomeEntity: 0x7fc5c55b6220> (entity: SomeEntity; id: 0x7fc5c5052b20 ... )}"; }
and exception = -[__NSCFType contextDidSave:]: unrecognized selector sent to instance 0x7fc5c505d940 with userInfo = (null)
I use a separate managed object context and fetch my managed objects inside this NSOperation.
Maybe it is something related to Core Data bugs or ARC? Maybe ARC cleans some of objects, that must be saved?
Because, without ARC everything was fine, all worked. When I turned on ARC - EXC_BAD_ACCESS.
Does anyone know why it occurs?
Maybe ARC deallocates some object that receives NSManagedObjectContextDidSaveNotification and this causes the exception?
I had something similar, and fixed it by making sure to removeObserver: before the object gets deallocated.
Note that the CoreData exception actually hides the notification center exception, so you don't get to see it.
I have a weird issue that comes up while releasing an object. In the object's dealloc method I am releasing another (sub) object. When this sub object is released I get an EXC_BAD_ACCESS error. I am pretty sure the sub-object is a valid pointer right before I call release on it.
This is how I've confirmed the weirdness - I set a break point inside the dealloc method, right before the release of the sub-object, and it is allocated! I can send it messages and it responds correctly. Another weird bug is that, if NSZombieEnabled is set to YES, I dont get an error at all, not even NSZombie's usual error that says I've sent a message to a deallocated object, the code runs properly.
Does anybody have any idea how to solve this?
Thanks in advance!
* EDIT 1 *
I've found out that if I place the [super dealloc] in the end of the dealloc, it crashes, but if I place it at start, it won't. I've had something similar before, only the other way - app crashed if I [super dealloc] in start of my dealloc, and didn't at the end.
Why does it make a difference and when should you use what?
* EDIT 2 *
Scratch Edit #1! It doesn't work either way.
Do your dealloc routine happen to look like this:
- (void)dealloc
{
[super dealloc];
[otherObject release];
}
if so, change the order. If you call [super dealloc], your object gets vanished from memory, trying to acces otherObject later will cause you to access non-allocated memory -> EXC_BAD_ACCESS.
Without seeing how the object is initialized, will be hard for anyone to know for sure.
MyObject *someObject = [MyObject alloc] init...]; // Make sure you aren't autoreleasing here
// do some stuff with someObject
[someObject release];
OK so I have a code with an class object called "game". Every frame (60 FPS) I update that object with function that gets a string. After like 5 seconds of running the game I'm getting the unrecognized selector sent to instance error.
The update:
[game updatePlayersAndMonsters:#"0" monsters:#"0"];
The function:
-(void)updatePlayersAndMonsters:(NSString*)players monsters:(NSString*)monsters {
CCLOG(#"%#.%#", players, monsters);
}
I don't understand what's going on.
The error:
2011-07-03 12:13:19.175 app[65708:207] -[NSCFString updatePlayersAndMonsters:monsters:]: unrecognized selector sent to instance 0xc4e95b0
2011-07-03 12:13:19.176 app[65708:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSCFString updatePlayersAndMonsters:monsters:]: unrecognized selector sent to instance 0xc4e95b0'
What should I do? Thanks. Also IDK if any other details you need, so just write if I forget something, I just don't have an idea.
UPDATE:
Gmae is object of class GameNode:
+(id) GmameNodeWithMapID:(int)MapID_ scene:(SomeScene*)MainScene_ players:(NSString*)Cplayers_ monsters:(NSString*)Cmonsters_ monsterCount:(NSString*)monsterCount_
{
return [[[self alloc] GmameNodeWithMapID:MapID_ scene:MainScene_ players:Cplayers_ monsters:Cmonsters_ monsterCount:monsterCount_] autorelease];
}
-(id) GmameNodeWithMapID:(int)MapID scene:(SomeScene*)MainScene players:(NSString*)Cplayers monsters:(NSString*)Cmonsters monsterCount:(NSString*)monsterCount
{
if( (self=[super init])) {
I create it with:
game = [GameNode GmameNodeWithMapID:ChoosenMapID scene:self players:Thing[5] monsters:Thing[6] monsterCount:Thing[4]];
UPDATE 2
I create the SomeScene:
+(id) scene {
CCScene *s = [CCScene node];
id node = [SomeScene node];
[s addChild:node];
return s;
}
-(id) init {
if( (self=[super init])) {
I use it:
[[CCDirector sharedDirector] replaceScene: [CCTransitionRadialCW transitionWithDuration:1.0f scene:[LoginScene scene]]];
Since you imply that the update function [game updatePlayersAndMonsters:#"0" monsters:#"0"]; is called for the first 5 seconds of your game and then you get the error, my guess is that the game object is not correctly retained, so it gets deallocated and the successive attempt of sending a message to it fails because some NSString object has been reusing its memory (and it does not have a updatePlayersAndMonsters:monsters selector).
Please share how game is created (alloc/init) and how it is stored in your classes to help you further.
Activating NSZombies tracking could also help to diagnose this.
EDIT: after you adding the code
It seems to me that in the line:
game = [GameNode GmameNodeWithMapID:ChoosenMapID scene:self players:Thing[5] monsters:Thing[6] monsterCount:Thing[4]];
you are setting either a local variable or an ivar to your autoreleased GameNode.
Now, since you are not using a property, nor I can see any retain on your autoreleased GameNode, my hypothesis seems confirmed. Either assign to a retain property:
self.game = [GameNode ...];
being game declared as:
#property (nonatomic, retain)...
or do a retain yourself:
game = [[GameNode GmameNodeWithMapID:ChoosenMapID scene:self players:Thing[5] monsters:Thing[6] monsterCount:Thing[4]] retain];
'NSInvalidArgumentException', reason: '-[NSCFString updatePlayersAndMonsters:monsters:]: means tht you are trying to send updatePlayersAndMonsters to a String object. Are you reassigning game to point to something else?
I'm getting this exception on the following code. I think it's because I have not defined the two incoming parameter types. They are local; so how do I define them (and where).
Error: 2011-04-27 11:18:03.226
PointPeek[174:707] * Terminating app
due to uncaught exception
'NSInvalidArgumentException', reason:
'+[SQLiteDB addRecordToDatabase::]:
unrecognized selector sent to class
0x1fe70'
Here's the calling line of code:
[SQLiteDB addRecordToDatabase:
symbol.data: symbol.typeName];
and here's the method I'm calling:
- (void) addRecordToDatabase:data: typeName {
NSString *insertCommand = [NSString stringWithFormat:#"INSERT INTO CardData (CARD_ID, CARD_NAME, CODE_VAL) VALUES ('/%#', '/%#', '/%#')", data, #"Test Card", typeName];
if(sqlite3_open_v2(cDatabasePath, &db, SQLITE_OPEN_READWRITE, NULL) == SQLITE_OK) {
}
Error: 2011-04-27 11:18:03.226
PointPeek[174:707] * Terminating app
due to uncaught exception
'NSInvalidArgumentException', reason:
'+[SQLiteDB addRecordToDatabase::]:
unrecognized selector sent to class
0x1fe70'
Basically, the "unrecognized selector sent to..." message means you tried to tell an object (or class) to do something it doesn't know how to do. ("selector" is another name for method).
You defined your method of the SQLiteDB class as an instance method:
- (void) addRecordToDatabase:data: typeName;
We know that because of the - in the method name (see Methods and Messaging and Class Interface). In the error message you got, notice that it began with a +, which means you attempted to call a method on the SQLiteDB class itself, rather than on an instance of that class.
In other words, you attempted to do this:
[SQLiteDB addRecordToDatabase: symbol.data: symbol.typeName];
when you needed to do something like this:
SQLiteDB *db = [[[SQLiteDB alloc] init] autorelease]; // an instance
[db addRecordToDatabase: symbol.data: symbol.typeName];
(Note that the previous 2 lines of code aren't all that useful in and of themselves. Presumably, instead of creating an instance of SQLiteDB in this method, you'd have it as an instance variable).
[SQLiteDB addRecordToDatabase: symbol.data: symbol.typeName];
That'd assume that addRecordToDabase:: is a class method, not an instance method.
Furthermore, that is an awful name for a method. Try something like:
- (void)addRecordWithData:(NSData*)aData andType:(NSString*)aType;
That is, bare :s are to be avoided and you should always specify the type of the parameter (and not fall back to id as you did here).
Finally, why aren't you using Core Data or, at the very least, FMDB? Raw SQLite is a waste of time.
SQLite is harder to write code for than Core Data, most likely. If you are a newbie to both, Core Data is a better return on investment of your time.
In any case, the questions in your comment indicate that you really need to start by understanding Objective-C. Apple provides an excellent language guide.