I ran 'analyze" in xcode on a current iOS project to try to track down a freeze issue and there are a number of memory alerts that I don't understand (screenshot of one below).
What is going on there: I have a custom ObjC class extending NSObject; in the init method I alloc/init an NSMutableArray and then in a loop, populate it with NSMutableArrays. This nested array is declared as a property and released in dealloc(). It lives for the life of the app.
Am I doing this wrong? I don't understand the alert#3: # object not referenced in this execution path and has a retain count of +1.
Since my class allocs the outer array, it owns it and will clean it up. Do the inner arrays need to be released?
Thanks for any tips - still new at this.
EDIT/ADDITION
Trying to stamp out the additional memory warnings I am getting so I thought I would add to the question here in the event someone stumbles upon this w/ the same issue.
I am getting the following alert with the code below (the 2nd line "[keyArray addObject: etc"). What is going on: I have a custom class (Key - based on NSObject) that I instance and store in an array. Based on answers to my previous question, I guess my alloc increases the retain count and then when it is added to the array, the retain count isn't decremented - so the memory warning occurs.
What is the proper way to handle something like this? Use a placeholder like this:
Key * k = [[Key alloc] initKeyWithPath:path isBlackKey:NO]];
[keyArray addObject: k];
[k release];
Is that the proper way to do it? Or is there I way to write the custom class to return an autoreleased obj? (thanks and sorry to be so long winded!).
Potential leak of an object allocated on line 460
Method returns an Objective-C object with a +1 retain count (owning reference)
Object allocated on line 460 is not referenced later in this execution path and has a retain count of +1 (object leaked)
-(void) addOctaveToArraysWithTransform:(CGAffineTransform*)trans andPath: (CGMutablePathRef) path
{
path = [self createCF_keyUsingTransform: trans];
[keyArray addObject:[[Key alloc] initKeyWithPath:path isBlackKey:NO]];
}
Key.h
#import <Foundation/Foundation.h>
#import "Key.h"
#interface Key : NSObject {
#public
CGMutablePathRef keyPath;
BOOL isBlackKey;
NSValue * path;
int keyState;
BOOL needsRedraw;
}
#property (nonatomic, assign) int keyState;
#property (nonatomic, assign) BOOL needsRedraw;
#property (nonatomic) CGMutablePathRef keyPath;
-(id) initKeyWithPath:(CGMutablePathRef) aPath isBlackKey:(BOOL)flag;
-(CGMutablePathRef) getKeyPath;
#end
Key.m
#import "Key.h"
#implementation Key
#synthesize keyState, needsRedraw, keyPath;
-(id) initKeyWithPath:(CGMutablePathRef) aPath isBlackKey:(BOOL)flag
{
if ((self = [super init])){
isBlackKey = flag;
keyState = 0;
needsRedraw = NO;
keyPath = aPath;
CGPathRetain(keyPath);
}
return self;
}
-(CGMutablePathRef) getKeyPath
{
return keyPath;
}
#end
Yes, you have to release the inner arrays to balance the alloc/init. Remember the outer array will retain each inner array, and the outer array will presumably release those later. But here you are still responsible for the alloc/init you just did.
Hope that helps.
You have an allocation of an NSMutableArray on each iteration of the for-loop. Instead use: NSMutableArray array] which is a convenience method that return an autoreleased NSMUtableArray suitable for adding to fieldNotes which will retain the NSMutableArray.
Related
I am trying to add keys in a dictionnary in Objective-C. The code is as follows :
I have a class MyClass whose header file contains :
#property (nonatomic) NSMutableDictionary *dict;
This gets initialized as follows :
_dict = [[NSMutableDictionary alloc] init];
Then I try to add keys to it :
- (void) addOrModify:(myKey*) key withValue:(myValue *) value {
[self.dict setObject:value forKey:key];
NSLog(#"Adding the key %# %p with value %# %p",[key description],key,[value description],value);
NSLog(#"%#",[self.dict description]);
}
And here is what I get upon adding different key/values :
Adding the key (key1) 0x7f9dc3590070 with value (value1) 0x7f9dc358e760
{
"(key1)" = "(value1)";
}
Adding the key (key2) 0x7f9dc357adc0 with value (value2) 0x7f9dc357de20
{
"(key2)" = (null);
"(key1)" = "(value1)";
}
Adding the key (key3) 0x7fa4d2cbdbd0 with value (value3) 0x7fa4d2d53cf0
{
"(key3)" = "(value3)";
"(key2)" = "(value2)";
"(key1)" = "(value1)";
}
Now if I take a look into the actual content of the dictionary with XCode's debugger, I find that all pairs key/value are present as they should. So it seems that the description method of dict fails to print correctly the value of some keys. The same happens without using NSLog but displaying the content of the dictionary in a UITable. Also note that if I try to log the address of the value for these particular keys, it also gives me 0x0 (so my description function is not at fault).
Note that the behavior is rather chaotic, sometimes several values are set to nil, then they appear correctly after I have added a few more pairs of key/values. I really can't get my head around this problem, any help would be much appreciated.
Edit 1
The interface of my keys
#interface myKey : NSObject <NSCopying>
#property(nonatomic, copy) NSString *myKeyName;
#property(nonatomic) float myKeyFloat;
#property(nonatomic, readonly, strong) NSDate *dateCreated;
The interface of my values:
typedef NS_ENUM(NSInteger, Unities) { g, kg, };
#interface myValue : NSObject
#property(nonatomic) float myValueFloat;
#property(nonatomic) Unities myValueUnit;
Calling code
- (IBAction)addKeyValue:(id)sender {
myValue *value = [myValue randomValue];
myKey *key =[[CatalogKeys sharedCatalogKeys]
getRandomKeyFromStore]; [self.dict addOrModify:key withValue: value];
}
where randomValue just set myValueUnit to 'g' and puts a random float in myValueFloat
This is a guess:
The information supplied does not show that your type myKey implements isEqual: and hash. Keys must implement these methods to work correctly in an NSDictionary; if they are not implemented the default NSObject implementations will be used and they probably do not produce the correct results for instances of myKey.
You also indicate that using the description of your myKey instances does work, this makes sense as description returns an NSString and that type implements isEqual: and hash.
HTH
I know there are a whole bunch of questions that have been asked and answered in stackoverflow about the challenge of getting keys in an NSDictionary sorted by putting those keys into sort order in an array. I understand that objects are not stored in sort order within the actual dictionary and that is, I think, for reasons of efficiency or maybe memory management on the part of Foundation code.
I have been working on trying out examples from several answers out here and in apple documentation and blogs (some I can get to work, others not!) , but I can't seem to find an example that solves my confusion.
I think my confusion is that the examples I'm encountering both here, in apple documentation and in the different helpful blogs, all seem to have examples where there is just a key value pair and the second value is not an object - it's more like just a value. (However isn't it really an object at some level? I would think it is)
One example, that I couldn't get to work (Sorting an NSArray by an NSDictionary value ) , uses this idea
[array sortedArrayUsingComparator:^(NSDictionary *item1, NSDictionary *item2) {
NSString *age1 = [item1 objectForKey:#"age"];
NSString *age2 = [item2 objectForKey:#"age"];
return [age1 compare:age2 options:NSNumericSearch];
}];
I thought maybe this idea, specifying the key in a more specific manner, might be my problem.
I wonder if maybe I'm not communicating to the compiler what the key is, and what the object is, and that is why I'm getting an "unrecognized selector sent to instance" error.
..... Code Snips Follow .....
1)
I have a class called "Dog". A given dog object has several properties, including an NSString key.
My key is "licenseString" is an alphanumeric key - I'm also wondering if I should use decimalNumberWithString but that's not the question here
#property (strong,nonatomic) NSString *licenseString;
#property (strong, nonatomic) NSString *dogName;
#property (strong, nonatomic) NSString *whatMakesDogSpecial;
#property (strong, nonatomic) UIImage *dogPhoto;
2) I have an NSDictionary
#property (nonatomic, strong) NSDictionary *dogDictionary;
I hardcode information into the dogDictionary in this not very sophisticated way,
Dog *aDog;
// Dog one
aDog = [[Dog alloc]init] ;
aDog.licenseString = #"1";
aDog.dogName = #"Oscar";
aDog.whatMakesDogSpecial = #"This animal was found at the Mid-Penn humane society. He is super friendly, plays well with other dogs and likes people too. He enjoys fetching balls and frisbees too. He also goes to the park daily." ;
aDog.dogPhoto = [UIImage imageNamed:#"webVuMiniAppDogOscar.jpg"];
[self.dogDictionary setValue:aDog forKey:aDog.licenseString];
3) Then once I have several dog objects in my dogDictionary, I want to sort on the license tag values, so that I can populate a table view with dog names, but by order of their license tags.
BTW it seems that the compiler does recognize "vars.dogDictionary" which appears in the code snip below, because when I look at the debugger I can see that two valid instances are coming up from my dog dictionary. The debugger output is in an attachment
So, using ideas from a stackoverflow answer and the apple documentation, I write this
NSArray *sortedKeys = [vars.dogDictionary keysSortedByValueUsingComparator:
^NSComparisonResult(id obj1, id obj2) {
return [obj1 compare:obj2];
}];
NSLog(#" The sorted array is %#", sortedKeys);
And that's where my problem happens. I recognize that 0x1182f740 refers to "obj1" as shown in the debugger attachment
2013-08-06 15:13:58.276 SortDogLIcenseTags[3876:11303] -[Dog compare:]: unrecognized selector sent to instance 0x1182f740
(lldb)
Attachment is a picture showing debugger values - they don't like to paste very well
Here's how I resolved this challenge. It works and was pretty straightforward to integrate into my Master/Detail project
I know I found a tutorial on the web somewhere that led me to this solution , I'm sorry I can't find it now.
Note that sortedDogDictionaryArray and dogDictionaryArray are declared as properties in the .h file.
self.dogDictionaryArray = [vars.dogDictionary allValues];
// Sort
NSSortDescriptor *sortDescriptorDog =
[[NSSortDescriptor alloc] initWithKey:#"licenseString" ascending:YES];
NSArray *sortDescriptorsDogs =
[NSArray arrayWithObject:sortDescriptorDog];
self.sortedDogDictionaryArray =
[self.dogDictionaryArray sortedArrayUsingDescriptors:sortDescriptorsDogs];
NSLog(#"%#",self.sortedDogDictionaryArray );
int doggie;
Dog *someDogName;
NSLog(#"Sorted Order is...");
for (doggie = 0; doggie < [self.sortedDogDictionaryArray count]; doggie++) {
//NSLog(#"%#", [sortedArray objectAtIndex:i]);
//NSLog(#"%#", [sortedArrayDogs objectAtIndex:doggie]);
someDogName = [self.sortedDogDictionaryArray objectAtIndex:doggie];
//NSLog(#"name is %#", someDogName.dogName);
NSLog(#"name is %# tag is %#", someDogName.dogName, someDogName.licenseString);
}
Trying to do something really simple, but can't figure out the syntax.
I have a class called Word.h which has 8 properties, strings and integers. For the sake of keeping things simple, I'll stick to 2 here:
#import <UIKit/UIKit.h>
#interface Word : NSObject
#property (nonatomic, strong) NSString *word;
#property (nonatomic, strong) NSNumber *wordLevel;
#end
Both properties are synthesised in the .m file
I then want to create some objects in another file (UIViewController). In the .h file I have this:
#import "Word.h"
and in the .m file, this:
Word *newWord = [[Word alloc] init];
[newWord setWord:#"theorise"];
[newWord setWordLevel:6];
Word *newWord1 = [[Word alloc] init];
[newWord setWord:#"implicit"];
[newWord setWordLevel:7];
Word *newWord2 = [[Word alloc] init];
[newWord setWord:#"incredible"];
[newWord setWordLevel:9];
I now get an error message "Implicit conversion of 'int' to 'NSNumber *' is disallowed with ARC"
What am I doing wrong...is the property defined incorrectly in the class file?? How do I access this property. It works fine with the string.
I will also want to access the properties later - how do I do that...for example:
cell.label1.text = [newWord2 wordLevel];
Is this the right syntax???
Hoping someone can help me, tearing clumps of hair out here!
M
You declared wordLevel to be an NSNumber, an object. You are treating it in your code like it is a plain C int. You have to decide which your want it to be and treat it that way consistently. For example, for a plain C int property you would instead declare:
#property (nonatomic, assign) int wordLevel;
On the other hand if you really want wordLevel to be an NSNumber you need to use the setter like this:
[newWord setWordLevel:[NSNumber numberWithInt:6]];
Im trying to set an array for a timer program im writing in xcode. the values are in seconds, and what i want is to have a button in the interface builder that starts a timer with that number of seconds. This is the struct im trying to declare to provide the times in a .h header file. its just an array with 2 arrays in it, that i could call with #collegeTimes.constructive or something similar.
Thanks in advance!
- (NSDictionary *)debateTimes;
id debateTimes = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSDictionary dictionaryWithObjectsAndKeys:
#"540", #"constructive",
#"360", #"rebuttal",
#"180", #"cx",
#"600", #"prep",
nil], #"collegeTimes",
[NSDictionary dictionaryWithObjectsAndKeys:
#"480", #"constructive",
#"300", #"rebuttal",
#"180", #"cx",
#"480", #"prep",
nil], #"hsTimes",
nil]; \\error is called here.
This is the struct im trying to declare to provide the times in a .h header file
This is the problem. You can not create constant NSDictionary objects (or most other NS objects, for that matter) outside of a function. One way to do what wou want would be as follows:
SomeThing.h
#interface SomeThing : NSObject
{
...
}
+ (NSDictionary *)debateTimes;
#end
SomeThing.m
static NSDictionary * staticDebateTimes = nil;
#implementation SomeThing
...
+ (NSDictionary *)debateTimes
{
if (staticDebateTimes == nil)
{
staticDebateTimes = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSDictionary dictionaryWithObjects:...
}
return staticDebateTimes;
}
#end
This code would now be used externally as follows:
NSDictionary * debateTimes = [SomeThing debateTimes];
You cannot assign an objective-c object to a variable outside of a function. When a variable is assigned outside a function, its value becomes part of the executable. Since the value of the pointer to a object is not known until runtime, you cannot assign the object until it is created. (Constant NSStrings are an exception to this as they are also part of the executable)
The best way to store a structure like this would be to use an array of c structures.
typedef struct {
char *name;
NSTimeInterval constructive;
NSTimeInterval rebuttal;
NSTimeInterval cx;
NSTimeInterval prep;
} DebateTime;
DebateTime[2] = {{"collegeTimes", 540, 360, 180, 600},
{"hsTimes", 480, 300, 180, 480}};
You can also change the name and time intervals to constant strings if you wish.
I have a problem with NSNumber: I don't understand how to increment and decrement it! I've tried int with [NSNumber intValue] and so on, but it didn't work!!!! I just want a page counter which can be converted to an NSNumber at the end.
My second problem is displaying a (partially) transparent image in an UIImageView. It has ever a (white) background.
Thanks for answering,
Le Milonkh
HI there
don't use nsnumbers, use ints. Much easier... (NSNumber is merely a wrapper for storing numbers, whereas int provides the default set of C based mathematical interfaces you are looking for, with relative ease - I'm sure you can do math with NSNumber -> although many people say NSDecimal is better. I say use floats, ints and doubles).
int pagenumber;
for(pagenumber = 0; pagenumber < 5; pagenumber++){
NSLog(#"%i", pagenumber);
}
then if you really need it in an NSNumber then do:
NSNumber *pagenumberns = [NSNumber numberWithInt:pagenumber];
In answer to your second question I have never had that problem, but try doing: [ImageView setOpaque:no] and [ImageView setBackgroundColor:[UIColor clearColor]];
Hope some of that helps.
Thank you for your answer, but I need to declare them globally in my ...ViewController.h & .m files because all my methods use them.
Is is possible to do it like that, or have I to #property and #synthesize the int?
FooViewController.h:
#interface FooViewController : UIViewController {
int *currentPage;
}
-(void)next;
-(void)changePage:(int)page;
FooViewController.m:
#implementation Post_GeheimnisViewController
#synthesize currentPage;
-(void)changePage:(int)page {
//do some stuff here
}
-(void)next {
currentPage++;
[self changePage:currentPage];
}
#end
Thank you for answering!
Le Milonkh