How can I customize the NSdictionary using Mantle? - objective-c

I have the following json string:
{"suit_id": 2427;
"suits": "http://img.prettyyes.com/1137-4930-1446175512.jpeg;http://img.prettyyes.com/1137-7665-1446175512.jpeg;http://img.prettyyes.com/1137-4783-1446175512.jpeg"}
So when use mantle to parse the json string with following file
testModel.h
#interface testModel : MTLModel <MTLJSONSerializing>
#property (nonatomic, strong) NSString *suit_id;
#property (nonatomic, strong) NSString *suits;
#end
testModel.m
#implementation testModel
+ (NSDictionary *) JSONKeyPathsByPropertyKey {
return #{
"suit_id": "suit_id",
"suits": "suits"
};
}
#end
How ever I would like to convert suits from string to a NSArray with multiple urls so I did following:
testModel.h
#interface testModel : MTLModel <MTLJSONSerializing>
#property (nonatomic, strong) NSString *suit_id;
#property (nonatomic, strong) NSArray *suits;
#end
testModel.m
#implementation testModel
+ (NSDictionary *) JSONKeyPathsByPropertyKey {
return #{
"suit_id": "suit_id",
"suits": "suits"
};
}
+ (NSValueTransformer *) suitsJSONTransform {
return [MTLValueTransformer transformerUsingForwardBlock:^(NSString *str, BOOL *success, NSError **error){
return [[str componentsSeparatedByString:#";"] mutableCopy];
}];
}
#end
But it's not working. The result is nil. When I override the wrong function?

The method returning the NSValueTransformer for suits should be called suitsJSONTransformer, not suitsJSONTransform.
The format for the method name is <propertyName>JSONTransformer.

Related

Thread 1 : EXC_BAD_ACCESS Code = 1, address = 0x13 Trying to get one property from my object

I'm trying to get identifier property from WSLanguage:NSManagerObject and I'm getting this error.
The error happened in the codition when I try to compare [lang.identifier intValue] == [[wordDic objectForKey:#"language"]intValue].
The error just happened on my iPad. In the iPhone it is working propertly.
What is happening?
for (NSDictionary * wordDic in wordsJson) {
for (WSLanguage * lang in langs){
if ([lang.identifier intValue] == [[wordDic objectForKey:#"language"]intValue]) {
for (WSCategory *cat in cats) {
if ([cat.identifier intValue] == [[wordDic objectForKey:#"category"]intValue]) {
WSWord *word = [self importWord:wordDic withLanguage:lang andCategory:cat];
[words addObject:word];
}
}
}
}
}
This is the WSLanguage class
#class WSLanguage;
#interface WSCategory : NSManagedObject
#property (nonatomic, retain) NSNumber * identifier;
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) WSLanguage * language;
#end

Creating Dictionary from a model that contains nil values

I have the following Model:
#interface Person : NSObject
#property (nonatomic, copy) NSString *firstName;
#property (nonatomic, copy) NSString *middleName;
#property (nonatomic, copy) NSString *lastName;
#property (nonatomic, copy) NSString *status;
#property (nonatomic, copy) NSString *favoriteMeal;
#property (nonatomic, copy) NSString *favoriteDrink;
#property (nonatomic, copy) NSString *favoriteShow;
#property (nonatomic, copy) NSString *favoriteMovie;
#property (nonatomic, copy) NSString *favoriteSport;
-(NSDictionary *)getSomeInfo;
-(NSDictionary *)getAllInfo;
#end
Part 1:
I want getSomeInfo to return NSDictionary (e.g. {"firstName", self.firstName}) for all the fields that does not contain nil. How can I do that? (I could check every value but I wonder if there's a better way)
Part 2:
I want getAllInfo to return NSDictionary with all the property and if one contains nil then it should throw an error. Again do I have to write a long conditional statement to check or is there a better way?
Note: I want to do this without using external library. I'm new to the language so I'm open to suggestions if there's a better pattern in Objective-C.
There are two approaches.
1) Check each value:
- (NSDictionary *)getSomeInfo {
NSMutableDictionary *res = [NSMutableDictionary dictionary];
if (self.firstName.length) {
res[#"firstName"] = self.firstName;
}
if (self.middleName.length) {
res[#"middleName"] = self.middleName;
}
// Repeat for all of the properties
return res;
}
2) Use KVC (Key-value coding):
- (NSDictionary *)getSomeInfo {
NSMutableDictionary *res = [NSMutableDictionary dictionary];
NSArray *properties = #[ #"firstName", #"middleName", #"lastName", ... ]; // list all of the properties
for (NSString *property in properties) {
NSString *value = [self valueForKey:property];
if (value.length) {
res[property] = value;
}
}
return res;
}
For the getAllInfo method you can do the same but instead return nil if any value is missing. Treat the nil results as your indication that not all properties have a value.

Can't use NSMutableArray data after Parsing with NSXMLParser (objective-c)

Hi I did parsing with NSXMLParser of some xml :
<company>
<name>Idan</name>
<country>Israel</country>
.....
<gender>man</gender>
</company>
I see that parsing success , now I have the MutableArray with one object that contain all strings (Idan,Israel etc.) but when I want to use this array, I can't get strings it contain.
When I do :
NSMutableArray *use = [pars users ];
NSLog(#"%#",use );
(users it's my array with object) I see:
<List:03f5a78>
where List in my code is:
#import <Foundation/Foundation.h>
#interface List : NSObject{
NSString *name;
NSString *country;
NSString *status;
NSString *gender;
}
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSString *country;
#property (nonatomic, strong) NSString *status;
#property (nonatomic, strong) NSString *gender;
#end
#import "List.h"
#implementation List
#synthesize name,date,city,country,status, gender;
#end
I try to do something like this:
NSMutableArray *use = [pars users.name ];
NSLog(#"%#",use );
but is not working, any ideas how to fix this?
Override the description method of your List class, and return a string which includes the values of all of the properties, then output it like you did the first time. The console will then print the value you returned.
Example:
#implementation List
...
...
-(NSString *)description
{
NSMutableString *desc = [NSMutableString string];
[desc appendFormat:#"name=%#, ", self.name];
[desc appendFormat:#"country=%#, ", self.country];
[desc appendFormat:#"status=%#, ", self.status];
[desc appendFormat:#"gender=%#", self.gender];
return desc
}
...
...
#end

serialize objective-c custom object to JSON for OSX?

I'm very new to Mac development and I'm having some troubles finding good resources. My current problem is a custom objective-c class object serialization to JSON.
I know that there is a built-in serializer in apple libraries, but that one works only with Foundation objects.
In my case I have my own class that looks like this:
#interface SomeClass : NSObject
{
int a;
int b;
NSString *aa;
NSString *bb;
}
#property int a,b;
#property NSString *aa,*bb;
#end
If anyone knows how to serialize this type of structure to a JSON please give me a hint! Any kind of relevant information would help! Thank you!
If you just want to serialize an object that contains integers and strings, the easiest way is to create a data structure that NSJSONSerialization supports and serialize that:
static const NSString *kAKey = #"a";
static const NSString *kBKey = #"b";
static const NSString *kAaKey = #"aa";
static const NSString *kBbKey = #"bb";
- (id)JSONObject {
return #{
kAKey: #(self.a),
kBKey: #(self.b),
kAaKey: self.aa,
kBbKey: self.bb
};
}
- (NSData *)JSONData {
return [NSJSONSerialization dataWithJSONObject:[self JSONObject] options:0 error:NULL];
}
I have been looking into this for the past week. I decided to write my own solution. It is very simple and built upon existing Apple functionality.
See here: https://github.com/gslinker/GSObject
And here: http://digerati-illuminatus.blogspot.com/2016/01/objective-c-and-json-convert-subclass.html
For your data model object have it inherit from GSObject instead of NSObject. Here is an example of ThingOne with inherits from GSObject:
ThingOne* object1 = [[ThingOne alloc] init];
object1.name = #"John Jones";
NSData* jsonData1 = [object1 toJsonDataWithOptions:NSJSONWritingPrettyPrinted];
NSString *jsonString1 = [object1 toJsonStringWithOptions:NSJSONWritingPrettyPrinted];
NSDictionary<NSString *,id> *dict1 = [GSObject dictionaryWithValues:object1];
NSString *roundTripJson1 = [object1 toJsonStringWithOptions:NSJSONWritingPrettyPrinted];
//
// ThingOne.h
// JasonStuff
//
// Created by Geoffrey Slinker on 12/28/15.
// Copyright © 2015 Slinkworks LLC. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "GSObject.h"
#import "ThingTwo.h"
#interface ThingOne : GSObject
#property (nonatomic, retain) NSString *name;
#property (nonatomic, retain) ThingTwo *thingTwo;
#property (nonatomic, retain) NSArray *values;
#property (nonatomic, retain) NSDictionary *dict;
#property int myInt;
#property float myFloat;
#property BOOL myBool;
#property (nonatomic, retain) NSNumber* someMoney;
#end
//
// ThingOne.m
// JasonStuff
//
// Created by Geoffrey Slinker on 12/28/15.
// Copyright © 2015 Slinkworks LLC. All rights reserved.
//
#import "ThingOne.h"
#implementation ThingOne
#synthesize name;
#synthesize thingTwo;
#synthesize values;
#synthesize dict;
#synthesize myInt;
#synthesize myFloat;
#synthesize myBool;
#synthesize someMoney;
- (instancetype)init
{
self = [super init];
thingTwo = [[ThingTwo alloc] init];
thingTwo.stuff = #"Thing Two Stuff";
thingTwo.someOtherStuff = #"Thing Two Other Stuff";
NSDateFormatter *dateFormater = [[NSDateFormatter alloc]init];
[dateFormater setDateFormat:#"yyyy-mm-dd"];
thingTwo.someDate = [dateFormater dateFromString:#"1963-10-07"];
values = [NSArray arrayWithObjects:#"Value1", #"Value2", #"Value3", nil];
dict = [NSDictionary dictionaryWithObjectsAndKeys:#"value1", #"key1", #"value2", #"key2", nil];
myInt = 5431;
myFloat = 123.456f;
myBool = YES;
someMoney = [NSNumber numberWithInt:503];
return self;
}
#end
//
// ThingTwo.h
// JasonStuff
//
// Created by Geoffrey Slinker on 12/28/15.
// Copyright © 2015 Slinkworks LLC. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "GSObject.h"
#interface ThingTwo : GSObject
#property (nonatomic, retain) NSString *stuff;
#property (nonatomic, retain) NSString *someOtherStuff;
#property (nonatomic, retain) NSDate *someDate;
#property (nonatomic, retain) NSString *nullString;
#property (nonatomic, retain) NSDate *nullDate;
#end
//
// ThingTwo.m
// JasonStuff
//
// Created by Geoffrey Slinker on 12/28/15.
// Copyright © 2015 Slinkworks LLC. All rights reserved.
//
#import "ThingTwo.h"
#implementation ThingTwo
#synthesize stuff;
#synthesize someOtherStuff;
#synthesize someDate;
- (instancetype)init
{
self = [super init];
someDate = [NSDate date];
return self;
}
#end
Here is an example of the JSON output:
{
"values" : [
"Value1",
"Value2",
"Value3"
],
"myInt" : 5431,
"myFloat" : 123.456,
"myBool" : true,
"someMoney" : "$503.00",
"thingTwo" : {
"stuff" : "Thing Two Stuff",
"nullDate" : null,
"someDate" : "1963-01-07 07:10:00 +0000",
"nullString" : null,
"someOtherStuff" : "Thing Two Other Stuff"
},
"name" : "John Jones",
"dict" : {
"key1" : "value1",
"key2" : "value2"
}
}

Store scalar values (NSInteger, BOOL, double) in CoreData without converting to NSNumber

I have read a lot of articles where they say to explicitely convert from and to NSNumber when I want to store scalars in CoreData:
#property (nonatomic, assign) NSInteger value;
- (NSInteger)value
{
return [value integerValue];
}
- (void)setValue:(NSInteger)val
{
value = [NSNumber numberWithInteger:val];
}
But in our old project we have a bunch of properties where we doesn't do those manipulations (and they don't have custom accessors)! Why it works?
Example code
Declaration. Scalar values are not transient.
#interface ProductProperty : NSManagedObject
#property (nonatomic, strong, readonly) NSString * propertyID;
#property (nonatomic, strong, readonly) NSString * title;
#property (nonatomic, strong, readonly) NSSet * values;
#property (nonatomic, assign, readonly) BOOL filter;
#property (nonatomic, strong, readonly) NSDate *update;
#property (nonatomic, strong, readonly) NSNumber *index;
#property (nonatomic, assign, readonly) BOOL system;
#end
#import "ProductProperty.h"
#implementation ProductProperty
#dynamic propertyID;
#dynamic title;
#dynamic values;
#dynamic filter;
#dynamic update;
#dynamic index;
#dynamic system;
#end
Mapping into objects. Called if received JSON differs from existing. Otherwise it fetches from the CoreData storage.
- (void)updateProperties:(NSArray*)properties
{
for (NSDictionary *_property in properties) {
NSString *propertyID = [_property objectForKey:#"id"];
ProductProperty *property = [state.productPropertiesWithIDs objectForKey:propertyID];
if (!property) {
property = [state.ctx newObjectWithEntityName:ProductProperty.entityName];
property.propertyID = propertyID;
[state.productPropertiesWithIDs setObject:property forKey:propertyID];
}
property.update = state.update;
property.title = [_property objectForKey:#"title"];
property.filter = [_property objectForKey:#"filter"] ? [[_property objectForKey:#"filter"] boolValue] : YES;
property.index = [propertyIndexes objectForKey:propertyID] ? [propertyIndexes objectForKey:propertyID] : [NSNumber numberWithInt:propertyIndex++];
property.system = [SYSTEM_PROPERTY_IDS containsObject:propertyID] ? YES : NO;
[self updatePropertyValues:[_property objectForKey:#"values"] forProperty:property];
}
}
- (ProductProperty*)productPropertyWithID:(NSString*)propertyId error:(NSError**)error
{
NSFetchRequest *req = [ProductProperty request];
req.predicate = [NSPredicate predicateWithFormat:#"propertyID == %#", propertyId];
return [[ctx executeFetchRequest:req error:error] lastObject];
}
The answer is that since iOS 5 CoreData support auto generating accessors for scalars so I don't need to implement them manually.