The return value of this method is returning null even though the dictionary being passed to is returning the correct data. In debug, I can see that dict is made up of 16 key/value pairs, but when it returns self, my object is returned with no data. I've looked at several examples and my code seems to be the same, but my method is not returning anything.
Any help is greatly appreciated
#import "STHsCardData.h"
#implementation STHsCardData
#synthesize name = _name;
-(instancetype)initWithDictionary: (NSDictionary*) dict{
if (self = [super init]) {
_name = [dict objectForKey:#"name"];
}
return self;
}
In this class, I initialize my STHsCardData object with the dictionary but the name property "newCard" object is always nil instead of the name of the card.
//Loop through data to get to each card object
for (NSDictionary *collection in data)
{
if (collection.count == 0)
{
NSLog(#"array is empty");
}
else
[setArray addObject:collection];
}
for (NSDictionary *set in setArray)
{
for (NSDictionary *cardObj in set){
STHsCardData *newCard = [[STHsCardData alloc]initWithDictionary:cardObj];
[cardArray addObject: newCard];
}
}
return cardArray;
}
#end
Without the data structure of the source of your data it's hard to tell exactly what's wrong. I suspect the issue is either in the nested-for loops you have for setArray and set - should there only be one loop there? Or the key is a different case such as "Name", "NAME", or that key doesn't exist.
It's all but impossible to debug data-driven code like this without feeding it data and walking it through the debugger. Why not add a log statement to see what's going on:
-(instancetype)initWithDictionary: (NSDictionary*) dict
{
if (self = [super init])
{
id nameFromDict = dict[#"name"];
NSLog(#"In initWithDictionary, dict[#"name"] = %#", nameFromDict];
_name = nameFromDict;
}
return self;
}
Related
NSMutableArray containsObject returns true even the address and data is different.
I've seen this post NSMutableArray containsObject returns true, but it shouldnt
already but still I'm not finding my solution:
Below is my scenario:
NSMutableArray *destClasses = [NSMutableArray array];
id sourceClasses = [dict objectForKey:#"Classes"];
if ([sourceClasses isKindOfClass:[NSArray class]]) {
for (NSDictionary *class in sourceClasses) {
MyClass *a = [[MyClass alloc] init];
[a arrangeClassWithDictionary:classDict]; //this methods assigns value to a from classDict
if (![destClasses containsObject:a]) {
[destClasses addObject:a];
}
}
}
In the first iteration destClasses adds an MyClass object and on the second iteration [destClasses containsObject:a] returns true even though the a has different address and different values assigned.
What I'm doing wrong here. Please help.
I got the answer.
containsObject: which sends the isEqual: message to every object it
contains with your object as the argument. It does not use == unless
the implementation of isEqual: relies on ==.
I've to override the isEqual: method to provide equality checking for my object fields like below,
- (BOOL)isEqual:(id)object
{
BOOL result = NO;
if ([class isKindOfClass:[self class]]) {
MyClass *otherObject = object;
result = [self.name isEqualToString:[otherObject name]];
}
return result;
}
I am getting data from Dictionary. It works well and stores data in NSMutableArray I want that before adding object into need to make sure that Array does not contain same object with Same Name and Type. Please see below.
Before inserting object we should check that it does not contain object with Type and Name if contains no need to insert.
NSArray *resultDic = [result1 objectForKey:#"results"];
for (int i = 0; i<[resultDic count]; i++) {
id item = [resultDic objectAtIndex:i];
NSDictionary *jsonDict = (NSDictionary *) item;
GetData *theObject =[[GetData alloc] init];
NSString*error = [jsonDict valueForKey:#"error"];
if(![error isEqualToString:#"No Record Found."])
{
[theObject setVaccineID:[jsonDict valueForKey:#"ID"]];
[theObject setVaccineName:[jsonDict valueForKey:#"Name"]];
[theObject setVaccinationType:[jsonDict valueForKey:#"Type"]];
[theObject setVaccineType:[jsonDict valueForKey:#"VType"]];
[theObject setFarmName:[jsonDict valueForKey:#"FName"]];
[theObject setDay:[jsonDict valueForKey:#"Day"]];
[theObject setAddedDateTime:[jsonDict valueForKey:#"DateTime"]];
[appDelegate.dataArray addObject:theObject];
}
}
A general purpose solution is to teach your GetData object how to compare itself to others. If they can be compared, then it will be easy to determine if a match is in any collection (and you might want to compare them in other contexts, too). Do this by implementing isEqual:. That might look something like this:
// in GetData.m
- (BOOL)isEqual:(id)object {
if ([object isKindOfClass:[GetData self]]) {
// assuming that the object is fully characterized by it's ID
return [self.vaccineId isEqual:((GetData *)object).vaccineId];
}
else {
return NO;
}
}
// have the hash value operate on the same characteristics as isEqual
- (NSUInteger)hash {
return [self.vaccineId hash];
}
With that done, you can take advantage of NSArray's containsObject:.
// ...
if(![appDelegate.dataArray containsObject:theObject] && ![error isEqualToString:#"No Record Found."])
// ...
If got a NSMutableDictionary from Json Data
NSMutableDictionary *returnedDict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
I know that this key returnedDict[#"data"][#"weather"][day][#"tides"] is NSNull in some cases. So I get -[NSNull objectForKeyedSubscript:]
So I try according to this answer How to check if an NSDictionary or NSMutableDictionary contains a key? to check if it is nil or not.
if (returnedDict[#"data"][#"weather"][day][#"tides"]){ some code }
and
if (returnedDict[#"data"][#"weather"][day][#"tides"]!=[NSNull null]){ some code}
does not avoid to run {some code}
How do I check this in the right way?
So your issue is:
Your server may return null to indicate that an object isn't present. NSJSONSerialization will convert that null into an instance of NSNull. In theory that means that instead of doing result[a][b][c] you need to check whether result[a] is a dictionary and, if so, whether result[a][b] is a dictionary, etc, etc, which is repetitious and error-prone?
Perhaps the easiest thing might be to remove from the dictionary any key with a value of NSNull, so that next time you ask for the value you'll get an ordinary nil, which is safe to message per the usual compound-messaging rules?
NSJSONSerialization won't do that for you but it's easy enough to add after the fact:
#interface NSDictionary(RemoveNullValues)
- (NSDictionary *)ty_collectionWithoutNullValues;
#end
#interface NSArray(RemoveNullValues)
- (NSArray *)ty_collectionWithoutNullValues;
#end
[...]
#implementation NSDictionary(RemoveNullValues)
- (NSDictionary *)ty_collectionWithoutNullValues {
NSMutableDictionary *reducedDictionary = [self mutableCopy];
// remove any keys for which NSNull is the direct value
NSArray *keysEvaluatingToNull = [self allKeysForObject:[NSNull null]];
[reducedDictionary removeObjectsForKeys:keysEvaluatingToNull];
// ask any child dictionaries to do the same; note that it's safe
// to mutate reducedDictionary in this array because allKeys is a
// copy property; what you're iterating is not reducedDictionary
// but a snapshot of its keys when the array first began
for (id key in [reducedDictionary allKeys]) {
id child = reducedDictionary[key];
if ([child respondsToSelector:#selector(ty_collectionWithoutNullValues)]) {
reducedDictionary[key] = [child ty_collectionWithoutNullValues];
}
}
return [reducedDictionary copy];
}
#end
#implementation NSArray(RemoveNullValues)
- (NSArray *)ty_collectionWithoutNullValues {
NSMutableArray *reducedArray = [NSMutableArray array];
for (id child in self) {
if ([child isKindOfClass:[NSNull class]]) continue;
if ([child respondsToSelector:#selector(ty_collectionWithoutNullValues)]) {
[reducedArray addObject:[child ty_collectionWithoutNullValues]];
} else {
[reducedArray addObject:child];
}
}
return [reducedArray copy];
}
#end
You must read this answer in conjunction with the accepted answer and comments to the question Is there NSMutableDictionary literal syntax to remove an element?
Following on from the linked answer you can quietly remove all the NSNull's and return nil instead if you access the element using the literal syntax (i.e. not using objectForKey:) by adding the following to your application:
#implementation NSDictionary (ClobberNSNull)
- (id) objectForKeyedSubscript:(id<NSCopying>)key
{
id result = [self objectForKey:key];
return result == NSNull.null ? nil : result;
}
#end
Now when you use the syntax:
dictionary[key]
if the matching object is NSNull then nil will be returned just as if the key did not exist.
There are caveats, see the linked question, and you need to decide if this approach is suitable for your situation. But it is simple.
HTH
Note: Before someone comments, NSNull is a singleton so the == is OK.
use
if(![returnedDict[#"data"][#"weather"][day][#"tides"] isKindOfClass:[NSNull class]]) { some code }
I have the following code in various parts of my app:
MyPFObjectSubclass *instance = [MyPFObjectSubclass object];
instance.myMutableArray = [NSMutableArray array];
instance.myMutableDictionary = [NSMutableDictionary array];
I am constantly forgetting to initialize these types, and running into problems later when I attempt setValue:forKey or addObject methods.
It's a nice-to-have, I admit, but I would like to play it safe and roll these initializations into +object if possible.
My PFObject subclasses all look roughly like this. I call [MyPFObject tlObject] to create a new instance.
#implementation MyPFObject
#dynamic objectUUID;
// Other fields
+ (MyPFObject*) tlObject
{
MyPFObject* obj = [self object];
[obj tlObjectInit];
// Other initializations
return obj;
}
+ (NSString*) parseClassName
{
return #"MyPFObject";
}
+ (PFQuery*) query
{
PFQuery* query = [PFQuery queryWithClassName: [self parseClassName]];
// Add includeKeys here
return query;
}
#end
I have a category on PFObject that includes tlObjectInit. The field objectUUID is there so that I have a value that can uniquely identify the object BEFORE IT IS SAVED. This is necessary because I sometimes create sets of objects that refer to one another. The Parse objectID is not set until it is saved.
#implementation PFObject (TL)
- (void) tlObjectInit
{
NSString* format = [[self parseClassName] stringByAppendingString: #"-%#"];
[self setObject: [NSUUID uuidStringInFormat: format]
forKey: #"objectUUID"];
}
// Add other initializations here
#end
In your MyPFObjectSubclass, override the init method:
-(instancetype) init
{
if (self = [super init])
{
_myMutableArray = [NSMutableArray array];
_myMutableDictionary = [NSMutableDictionary dictionary];
}
return self;
}
I guess your object method call one way or the other the init method.
Edit:
It looks like you use the Parse framework. As told in the reference, the PFObject init method shouldn't be overridden by subclasses.
I have to send a data by post in JSON format. I have my nsdictionary with keys and values.
NSDictionary *params_country=[NSDictionary dictionaryWithObjectsAndKeys:
#"1111",#"#id",
nil];
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
#"dummy3", #"#name",
#"dummy3#example.com", #"#mail",
#"password",#"#password", params_country,#"country",
nil];
When i am doing a log
DLog(#"params %#",[params description]);
I am getting the following
params {
"#mail" = "dummy3#example.com";
"#name" = dummy3;
"#password" = password;
}
The problem is that i have to sent the JSON in the order that i have listed in the above initialisation of my nsdictionary but the keys are being sorted somehow.
Any solution?
EDIT
Sorry i am sending a nsdictionary also in the params. If i remove the country then its fine.
Dictionaries are an unordered collection type. If you need to maintain a certain order, then you should use an ordered collection type like NSArray. But for this, your web service shouldn't care about the order, since it should be looking up the values by the keys provided.
As per some of the comments, this requirement does not match a valid JSON object as the official JSON Specification states:
An object is an unordered set of name/value pairs. An object begins with { (left brace) and ends with } (right brace). Each name is followed by : (colon) and the name/value pairs are separated by , (comma).
Unfortunately we don't live in a perfect world with perfect web services and there are often certain things that are out of our control.
I wrote a subclass of NSMutableDictionary after reading up on the internet that will order the dictionary based on the order you call setValue:forKey:.
I put the class into a gist you can download from here: https://gist.github.com/liamnichols/7869468 or you can just copy it from below:
LNOrderedMutableDictionary.h
#interface LNOrderedMutableDictionary : NSMutableDictionary
///If `anObject` is nil, it will not be added to the dictionary.
- (void)setNothingIfNil:(id)anObject forKey:(id)aKey;
#end
LNOrderedMutableDictionary.m
#import "LNOrderedMutableDictionary.h"
#interface LNOrderedMutableDictionary ()
#property (nonatomic, strong) NSMutableDictionary *dictionary;
#property (nonatomic, strong) NSMutableOrderedSet *array;
#end
#implementation LNOrderedMutableDictionary
- (id)initWithCapacity:(NSUInteger)capacity
{
self = [super init];
if (self != nil)
{
self.dictionary = [[NSMutableDictionary alloc] initWithCapacity:capacity];
self.array = [[NSMutableOrderedSet alloc] initWithCapacity:capacity];
}
return self;
}
- (id)init
{
self = [self initWithCapacity:0];
if (self)
{
}
return self;
}
- (void)setObject:(id)anObject forKey:(id)aKey
{
[self.array removeObject:aKey];
[self.array addObject:aKey];
[self.dictionary setObject:anObject forKey:aKey];
}
- (void)setNothingIfNil:(id)anObject forKey:(id)aKey
{
if (anObject != nil)
[self setObject:anObject forKey:aKey];
}
- (void)removeObjectForKey:(id)aKey
{
[self.dictionary removeObjectForKey:aKey];
[self.array removeObject:aKey];
}
- (NSUInteger)count
{
return [self.dictionary count];
}
- (id)objectForKey:(id)aKey
{
return [self.dictionary objectForKey:aKey];
}
- (NSEnumerator *)keyEnumerator
{
return [self.array objectEnumerator];
}
#end
If possible, your web service shouldn't have to rely on the JSON objects to be formatted in a specific order but if there is nothing you can do to change this then the above solution is what you are looking for.
Source: cocoawithlove