Content of a NSMutableDictionnary erratically returned - cocoa

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

Related

Realm cannot sort properly for capital letter in Xcode

Realm cannot sort properly for capital letter in Xcode. I've wrote following Realm to sort by according speaker name.
RLMResults *speakers = [[SpeakerDB objectsWhere:condition] sortedResultsUsingProperty:property ascending:YES];
It's correctly sorted when all are small and capital letter. But when those mixed with both small and capital letter, sorting got wrong.
Choun-Ki JOO
Chul Young CHOI
CHAN Wing Kwong << it gone wrong sorted.
CHEE Soon Phaik
Connie LAI
Please let me know how to solve that issue.
Realm doesn't support case-insensitive sorting, currently.
See also... https://github.com/realm/realm-cocoa/issues/2970
If you'd like to get a result sorted when all are a small or a capital letter, you should add a property for sorting. The property stores same value as the speaker name property but it contains all small letters(or all uppercase). Like the following:
#interface SpeakerDB : RLMObject
#property (nonatomic) NSString *name;
#property NSString *acturalName;
#property NSString *lowercaseMame;
#end
#implementation SpeakerDB
+ (NSArray<NSString *> *)ignoredProperties {
return #[#"name"];
}
- (void)setName:(NSString *)name {
_name = name;
self.acturalName = name;
self.lowercaseMame = [name lowercaseString];
}
#end
(To override the setter, defining the name property as ignoredProperty.)
Then you can sort by lowercaseMame.
RLMResults *speakers = [[SpeakerDB objectsWhere:condition]
sortedResultsUsingProperty:#"lowercaseMame" ascending:YES];

The Idea? creating sorted array from NSDictionary key values (with objects)

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);
}

NSMutable Array and objectAtIndex not working - only displays last item in array

Ok this is third day of working with Xcode so please be nice.
I am trying to set up a simple table to display records from an existing sqlite database. I've got as far as loading the database into a NSMutableArray and have verified the size is correct, but I can't loop through it and get the data properly out. All that displays is the last record of the table.
Here is the sample code:
while([results next]) {
self.subject_id = [results stringForColumn:#"SUBJECT_ID"];
self.subject = [results stringForColumn:#"SUBJECT"];
self.category = [results stringForColumn:#"CATEGORY"];
[subjects addObject:self];
NSLog(#"AFTER record: %# - %# - %#", self.subject_id, self.subject, self.category);
}
As the loop prints out to the log I verify that the correct data is being looped through.
Then I run this immediately after populating the array and I get the same last entry, each time:
//PULL UP THE THINGY AND SEE IF IT WORKS
Subject *sub;
int x = 0;
for (sub in subjects){
Subject *xsub = [subjects objectAtIndex:x];
NSLog(#" %i sub data ------- %#, ----- %#", x, xsub.subject, xsub.category);
x = x+1;
};
sub = [subjects objectAtIndex:50];
NSLog(#" sub data ------- %#, ----- %#", sub.subject, sub.category);
I even tried specifically pulling up a record from the Array like this but I get the same last record instead of the record I asked for:
sub = [subjects objectAtIndex:50];
"Subject" is a class giving the field names of my table. I haven't used the entity feature yet.
My header file declares the field names like this:
#property (nonatomic, retain) NSString * subject_id;
#property (nonatomic, retain) NSString * subject;
#property (nonatomic, retain) NSString * category;
I used the FMDB wrapper to get the data from my database and pieced together the classes from a couple different tableView examples such as the Animals one.
Can anyone give me some direction on how to debug this?
My guess would be either that each array object has had the same text loaded into it, or that the same object has been added to the array multiple times.
Either way, I'd take a long hard look at the array loading code.

analyze and memory alerts in xcode

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.

Array Values in Cocoa App - Initializer not constant error

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.

Resources