CFDictionary objectForKey message sent to deallocated instance - objective-c

Does anyone know why this could be happening?
The error clearly says that it's trying to access objectForKey of a dictionary that has been deallocated. However in the stack trace I don't see any dictionary. How is this possible?
So here's the code:
-(CGSize)sizeConstrainedToSize:(CGSize)maxSize fitRange:(NSRange*)fitRange {
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)self);
CFRange fitCFRange = CFRangeMake(0,0);
CGSize sz = CTFramesetterSuggestFrameSizeWithConstraints(framesetter,CFRangeMake(0,0),NULL,maxSize,&fitCFRange);
if (framesetter) CFRelease(framesetter);
if (fitRange) *fitRange = NSMakeRange(fitCFRange.location, fitCFRange.length);
return CGSizeMake( floorf(sz.width+1) , floorf(sz.height+1) ); // take 1pt of margin for security
}
UPDATE:
Turns out this is a problem on NSCache:
#implementation NSCache (SharedCache)
+(NSCache*)sharedCache;
{
static NSCache* sharedCache = nil;
if (sharedCache == nil) {
sharedCache = [[[self alloc] init] retain];
[sharedCache setCountLimit:0];
}
return sharedCache;
}
if I removed the retain there it crashes..
it basically crashes here:
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)self);
with that exception.

One of the properties or member variables is or contains a dictionary which has been deallocated. You might have code that is setting an attributes dictionary on the attributed string which is being over released.
Ultimately, the code you are highlighting is identifying an over released object but is not the crashing code. You need to find where the object is being over released. I recommend using Xcode performance tools, specifically the Zombies tool, to identify this crash. It's simulator only though so this will need to be reproduceable in the simulator to use the zombies tool.

Related

BAD_ACCESS crash unless I create a string with # - Using ARC [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
If I pass testString2 to the next view controller (where the string is assigned to a property of a NSManagedObject subclass), the app crashes soon after with a BAD_ACCESS error. I was able to determine the string was turning into a zombie a while after attaching it to the managed object and also assigning it to a class member of the receiving view controller, to try and eliminate this problem. However, it doesn't turn into a zombie until well after it has been assigned as described.
IF, however, I send testString instead of testString2 to the next view controller, no crashes and everything is happy. Incidentally, newKw is text from a text field, but using strings retrieved from a dictionary gives the same result. I have also tried using [NSString stringWithString:newKw] and other NSString methods in an attempt to create a brand new string, and I get the same result then too.
If I send nil instead of sending any string, there are no errors.
The managed object is never lost or corrupted if I pass testString. But if I pass testString2, it appears when the variable turns into a zombie, it takes out the managed object too because everything in the description is gone and is not shown as a fault. Following some other advice I have seen, I set a breakpoint for malloc_error_break, and in my log I see this:
Power Passage(3734,0x2dae1a8) malloc: *** error for object 0x9aa67b0: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Here is where it is passed from the VC where the string originated:
if (proceed) {
NSString *testString = #"testing123";
NSString *testString2 = newKw;
[self.navigationController pushViewController:[[NewKeywordSummary alloc] initWithKeyword:testString2] animated:YES];
Here is the property where the pointer is getting stored in the managed object:
#property (nonatomic, retain) NSString * newKeyword;
Here is the method newKw is being sent to:
-(instancetype)initWithKeyword:(NSString *)kw
{
if (self = [self init]) {
//Create a new request
kwReq = [ppKeywordRequest keywordRequestInContext:editingContext];
newKw = kw;
kwReq.newKeyword = newKw;
}
return self;
}
Then the kwReq object is passed to the next VC:
-(void)viewBtnHandler:(UIButton *)btn
{
if (btn == addNewTagBtn) {
[self.navigationController pushViewController:[[TagSummaryVC alloc] initWithKeywordRequest:kwReq tagSubmission:nil] animated:YES];
}
}
and it goes here:
-(instancetype)initWithKeywordRequest:(ppKeywordRequest *)req tagSubmission:(ppTagSubmission *)t
{
if (self = [super init]) {
delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
user = delegate.user;
phrases = [delegate.languagePhrases objectForKey:#"TagSummaryVC"];
if (req) {
editingContext = req.managedObjectContext;
kwReq = req;
}
else {
editingContext = [[NSManagedObjectContext alloc] init];
[editingContext setPersistentStoreCoordinator:[delegate.localDataContext persistentStoreCoordinator]];
delegate.editingContext = editingContext;
}
if (!t) {
ts = [ppTagSubmission tagSubmissionInContext:editingContext];
newTS = YES;
}
else
ts = (id)[editingContext objectWithID:[t objectID]];
self.navigationItem.backBarButtonItem =
[[UIBarButtonItem alloc] initWithTitle:#""
style:UIBarButtonItemStyleBordered
target:nil
action:nil];
}
return self;
}
And it returns to NewKeywordSummary here:
if (alertView.tag == AttachAlert) {
if (index == 0)
return;
NSString *testString = kwReq.newKeyword;
NSLog([NSString stringWithFormat:#"Test variable is %#", kwReq.newKeyword]);
[kwReq addTagSubmissionsObject:ts];
[self.navigationController popViewControllerAnimated:YES];
}
}
My NSLogs before and after it is a zombie:
2014-08-04 21:00:52.306 Power Passage[3838:60b] Test variable is vcxvzcx
2014-08-04 21:00:53.378 Power Passage[3838:60b] Test variable is vcxvzcx
2014-08-04 21:00:55.908 Power Passage[3838:60b] Test variable is <__NSMallocBlock__: 0x8ea4b00>
(lldb)
Make sure your NSString references are assigned to a #property on your classes (plenty of examples of assigning and using properties on iOS) using an appropriate storage type (strong or retain, for example). And, yes you are correct any "standard" string in an iOS app is usually an instance of NSString, and thus required the "#" symbol in front.
Try setting a break point on Exceptions ... this will help you identify the offending statement.
I would suggest picking up a book on an intro to Objective-C / iOS / iPad development ... I think you'll find the information invaluable and a HUGE time saver.
I believe I have found the answer to my question. I ran into this post:
why can't I declare a variable like "newVariable" in Obj-C?
Quote from the link:"Objective-C has a naming convention for memory management that is enforced by the compiler. Methods that start with new (also "alloc", "copy", "mutableCopy") are required to return an object that will be "owned" by the caller. See the documentation." (thanks progrmr!)
and realized that I had a property that started with "new", and while it wasn't being synthesized it WAS generating setters/getters with #dynamic... so every time the member kwReq.newKeyword was referenced on my managed object, I am guessing that the compiler was trying to change ownership or otherwise alter the retain count - so after a couple times I was out of retains. So I changed the member name to reqKw, and I have no more problem. I was NOT getting any kind of warning on this.(thanks Apple:-)

How can I silence Xcode anaylzer reporting "potential leak of an object stored into 'self'" for class method [duplicate]

This question already has an answer here:
Self managing/releasing objects reported as "Potential leak of object" under Xcode -> Product -> Analyse
(1 answer)
Closed 9 years ago.
I am almost certain that I don't have a leak in this code, yet the Xcode analyzer reports that there is a "potential" leak (Xcode 4.6.1).
+ (MySHA1hash *)sha1HashWithHashBytes:(unsigned char *)hash length:(unsigned int)length;
{
return [[[MySHA1hash alloc] initWithHashBytes:hash length:length] autorelease];
}
If the problem is that Xcode is reporting a false positive, I would like to figure out how to structure the code in a way to silence the warning.
It is also the possible that I am leaking in a way I don't understand, but If someone can see how I am actually leaking I would be glad to get that feedback as well.
This must have something to do with the init functions I call, because if I simply replace initWithHashBytes with init, then the leak is no longer reported. To that end I also include the body of initWithHashBytes.
- (id)initWithHashBytes:(unsigned char *)hash length:(unsigned int)length
{
if (hash != nil && length <= SHA_DIGEST_LENGTH) {
NSData *data = [NSData dataWithBytes:hash length:length];
self = [self initWithHash:data];
}
else {
self = nil;
}
return self;
}
- (id)initWithHash:(NSData *)hash
{
if ([hash length] <= SHA_DIGEST_LENGTH && (self = [super init]) != nil) {
finished = YES;
[hash getBytes:sha_Result];
hashValue = [NSNumber numberWithInt:[hash hash]];
}
else {
self = nil;
}
return self;
}
The line
self = nil;
in initWithHashBytes: (and initWithHash:) is the issue. You are allocating an object, but if you return nil from from initWithHashBytes:, that object will be leaked, because you'll call autorelease on nil rather than on the object you allocated.
Release self before you return nil and all should be good.
In this particular case there was obviously an error that needed to be fixed, but I have seen at times a need to suppress warnings that are completely understood to be non problems (i.e. a leak reported that is not actually a leak).
This is what I expected to need to do here, but it turned out that there was an actual leak. So I am glad it got fixed. I immediately found another problem that was a clear an unmistakable "false positive" (I know that the error is reported as a "potential leak" so in reality it isn't a false positive, but it doesn't mean I want to see it in the report every time I run the analyzer).
Because of this I still had the question of how to suppress these warnings. It turns out you can easily wrap code that you want the analyzer to bypass in a ifdef check for __clang_analyzer.
#ifndef __clang_analyzer__
... code you want to ignore ...
#endif
There was a very good write up on this here.
You are missing a [self release] before self = nil.
The object you get from alloc has a reference count of +1 which needs to be balanced by a call to release or autorelease. For the case where you return your actual object from sha1HashWithHashBytes:length: the autorelease in that class method takes care of everything.
For the case you return nil your init method is the last one that has a reference to that allocated object so it has to release it.

Why does my NSArray get deallocated?

I'm trying to understand Automatic Reference Counting, as I come from a high-level programming language (Python) and I'm working on a project which use this feature of Objective-C. I often get problems with ARC deallocating objects which I need later, but now I got a concrete example for which I hope I'll get an explanation.
- (void) animateGun:(UIImageView *)gun withFilmStrip:(UIImage *)filmstrip{
NSMutableArray *frames = [[NSMutableArray alloc] init];
NSInteger framesno = filmstrip.size.width / gun_width;
for (int x=0; x<framesno; x++){
CGImageRef cFrame = CGImageCreateWithImageInRect(filmstrip.CGImage, CGRectMake(x * gun_width, 0, gun_width, gun_height));
[frames addObject:[UIImage imageWithCGImage:cFrame]];
CGImageRelease(cFrame);
}
gun.image = [frames objectAtIndex:0];
gun.animationImages = frames;
gun.animationDuration = .8;
gun.animationRepeatCount = 1;
[gun startAnimating];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(arc4random() % 300)/100 * NSEC_PER_SEC), dispatch_get_current_queue(),^{
[self animateGun:leftGun withFilmStrip:[self getFilmStripForAction:gunShoot andTeam:nil withWeapon:nil]];
});
}
The idea behind this snippet of code is simple: I have a (UIImageView*)gun which I animate with the images stored in (NSMutableArray *)frames, at random times. (UIImage *)filmstrip is just an image which contains all the frames which will be used on animation. The first iteration of animation works, but the problems appears on the second iteration, where I get -[UIImage _isResizable]: message sent to deallocated instance ... or -[UIImage _contentStretchInPixels]: message sent to deallocated instance ... or -[NSArrayI release]: message sent to deallocated instance .... This happens at
gun.animationImages = frames;
but I don't understand why. I'm not requesting a fix for my issue, but just to help me understand what's happening here. Thanks.
ARC is a mechanism that removes the need to manually retain/release objects. Here's a nice site that explains how this works: http://longweekendmobile.com/2011/09/07/objc-automatic-reference-counting-in-xcode-explained/
Try changing "leftGun" for "gun". I think that's probably the one that gets deallocated at some point, if you're using it through an ivar. Otherwise, leftGun simply isn't in the scope.
Here's what it should look like:
In your .h file:
#property (nonatomic, strong) IBOutlet UIImageView *leftGun;
In your .m file:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(arc4random() % 300)/100 * NSEC_PER_SEC), dispatch_get_current_queue(),^{
[self animateGun:gun withFilmStrip:[self getFilmStripForAction:gunShoot andTeam:nil withWeapon:nil]];
});
Also, not quite sure where "gunShoot" is coming from. Is that supposed to be an enum?
EDIT
Added an example of how the leftGun property should be defined. The reason behind using a property over an ivar is for memory management purposes. If you want to release or destroy an object that is a property, simply set it to nil and the property will take care of releasing the object if it has to.
You may prevent the deallocation of the frames array if you mark it as __block.
__block NSMutableArray *frames = [NSMutableArray array];
see “The __block Storage Type.”

NSMutableDictionary Singleton issue

I am coding Objective-C using the Cocos2D framework, and I have a singleton used for multiple purposes. One new purposes is to get and set character's "states" which are strings. I've recently made an NSDictionary for this purpose, but I have issues with the program freezing up when a method inside the singleton is called.
Here's the singleton code. I'm just leaving in the character state stuff:
.h
#interface ExGlobal : NSObject {
NSArray *charStates_keys;
NSArray *charStates_objects;
NSMutableDictionary *charStates;
}
#property(nonatomic, retain) NSMutableDictionary *charStates;
+(ExGlobal*)sharedSingleton;
- (NSString *)charState:(NSString *)charName;
- (void)set_charState:(NSString *)value forCharName:(NSString *)charName;
#end
.m
#import "ExGlobal.h"
#implementation ExGlobal
#synthesize charStates;
static ExGlobal* _sharedSingleton = nil;
+(ExGlobal*)sharedSingleton {
#synchronized([ExGlobal class]) {
if (!_sharedSingleton) {
[[self alloc] init];
}
return _sharedSingleton;
}
return nil;
}
+(id)alloc {
#synchronized([ExGlobal class]) {
NSAssert(_sharedSingleton == nil, #"Attempted to allocate a second instance of a singleton.");
_sharedSingleton = [super alloc];
return _sharedSingleton;
}
return nil;
}
-(id)init {
self = [super init];
if (self != nil) {
// initialize stuff here
exitName = #"ruinsSkyMid";
sceneChangeKind = #"reborn";
charStates = [[NSMutableDictionary alloc] init];
charStates_keys = [NSArray arrayWithObjects:#"Feathers", #"Hummus", nil];
charStates_objects = [NSArray arrayWithObjects:#"at wall", #"with Feathers", nil];
charStates = [NSMutableDictionary dictionaryWithObjects:charStates_objects forKeys:charStates_keys];
}
return self;
}
- (NSString *)charState:(NSString *)charName{
NSString *value = [charStates objectForKey:charName];
return value;
}
- (void)set_charState:(NSString *)charState forCharName:(NSString *)charName{
[charStates setObject:charState forKey:charName];
}
- (void)dealloc {
//I know it doesn't get called, but just in case
[charStates release];
[super dealloc];
}
#end
It's unclear to me what exactly the issue is when it freezes. When this happens, all I get in the console is:
Program received signal: “EXC_BAD_ACCESS”.
warning: Unable to read symbols for /Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.3.5 (8L1)/Symbols/Developer/usr/lib/libXcodeDebuggerSupport.dylib (file not found).
Previous frame inner to this frame (gdb could not unwind past this frame)
Previous frame inner to this frame (gdb could not unwind past this frame)
Which I'm sure doesn't help finding the issue. I found if I redefine charStates_keys, charStates_objects and charStates inside both the charState and set_charState methods, it seems to work without freezing, except set_charState does not change the state.
It isn't freezing, it is crashing. Hence the EXC_BAD_ACCESS. It looks like your Xcode installation is borked, too, as the two messages following should not happen.
Note that methods should not have _s in the name; not a cause of the problem, but a comment on following convention.
You aren't retaining charStates and that is likely the cause of the crash.
Not an answer as such but I didn't have enough space in the comments field above to post this, but it might be useful.
As bbum already said, your lack of retaining charStates is likely the problem.
If you are confused about when to retain and not retain objects there's a really good book called "Learn Objective-C on the Mac" and I know it's a Mac book but most of it applies to iPhone too. On page 171 of chapter 9 (Memory Management) it talks about the "Memory Management Rules" and how if you are confused about when to retain or not then you don't understand the simple rules of Objective C memory management.
Essentially if you create an object using new, alloc or copy, then the retain count is automatically set to 1 so the object is retained and does not require you to retain it and will require a subsequent release to deallocate.
If you create the object any other way then the object will be an autoreleased object.
Obviously these rules only apply within the standard iOS libraries and can't necessarily be applied to third party libraries.
I recommend anyone who doesn't fully understand memory management in Objective C read this book. I found highly enlightening even for my iPhone work.
Hope that helps/.

Setting object to nil after release -- TT_RELEASE_SAFELY

I have started to study Three20 and I have a simple question about TT_RELEASE_SAFELY
Up till now I like to write code in this way:
UILabel *lab = [[UILabel alloc] initWithFrame:rect];
[self.view addSubview:lab];
[lab release];
Here I think the main pool is responsible to free the memory of lab.
Now I have found TT_RELEASE_SAFELY which is defined like so:
#define TT_RELEASE_SAFELY(__POINTER) { [__POINTER release]; __POINTER = nil; }
As you can see, after release, it sets the object to nil.
I'd like to know the difference between the two ways and which way is better.
Thanks.
Sending a message to nil is valid in Objective-C. Sending a message to a deallocated object is not.
Sending a message to a deallocated object:
id obj = [[MyClass alloc] init];
[obj release];
[obj doSomething]; // Crash!
Sending a message to nil:
id obj = [[MyClass alloc] init];
[obj release], obj = nil;
[obj doSomething]; // Valid
Assigning nil to a variable after an object has been deallocated is controversial because it can prevent you from realizing that something is wrong. Sedate Alien's example:
[controlCenter dealloc];
...
float timeLeft = [controlCenter timeToWaitBeforeBombDetonation];
This code will crash since controlCenter has been deallocated. As a result this defect will be detected and fixed early.
[controlCenter dealloc], controlCenter = nil;
...
float timeLeft = [controlCenter timeToWaitBeforeBombDetonation];
This code will assign 0.0 to timeLeft which appears to be a valid wait time even though controlCenter is nil.
Take the above with a grain of salt, since if you are writing an Objective-C app, you are probably more concerned with keeping your users happy by avoiding crashes than destroying cities. If the latter is a concern, you should probably be using a type-safe language like Ada.
I believe that using these variants of "safe releases" is an expressly bad idea.
Your application will fail in silent and mysterious ways, as messages passed to nil will not raise any warnings. It's much better to not nil out your references and take advantage of all that NSZombieEnabled has to offer.
The only difference is that TT_RELEASE_SAFELY sets the pointer to nil after release, so the reference won't be used after release. The pattern is a good one to follow and the TT_RELEASE_SAFELY macro makes it simpler to implement.