Serialize JSONModel - How to convert custom object to JSON in iOS? - ios

How to serialize a custom object with JSONModel ?
#property(nonatomic,strong) NSString<Optional> * tag_post_type;
#property(nonatomic,strong) NSString<Optional> * tag_users_type;
#property(nonatomic,strong) NSArray<Optional> * tags;
#property(nonatomic,strong) NSMutableArray<TagMediaModel*>* tag_posts;
#property(nonatomic,strong) NSMutableArray<TagLocationModel*>* locations;
I try to create a JSON file out of my custom Object with the JSONModel framework for iOS. I get the Error:
EXCEPTION: Invalid type in JSON write (TagMediaModel)
When I call toJSONString Method, I got this issue.
[tagAutomaticModel toJSONString];
This is the model data:
locations = (
"<TagLocationModel> \n [id]: 780307344\n [name]: Hotel Central Park, india\n</TagLocationModel>",
"<TagLocationModel> \n [id]: 463004401\n [name]: Miraj Cinema new year\n</TagLocationModel>",
"<TagLocationModel> \n [id]: 246187965\n [name]: Surya Treasure Island asia\n</TagLocationModel>",
);
"tag_posts" = (
"<TagMediaModel> \n [media_code]: BS0tQeFhU_Z\n [media_id]: 1492016420475981785\n [media_url]: https://scontent.cdninstagram.com/t51.2885-15/e15/17881459_...\n [media_type]: I\n</TagMediaModel>"
);

#property(nonatomic,strong) NSMutableArray<TagMediaModel>* tag_posts;
made few change as above, just removed the star in TagMediaModel.

The angle brackets after NSMutableArray contain a protocol. As #R.Mohan said, you need to remove * pointer and use without pointer.
The protocol must be in place. So add #protocol tag_posts and #protocol locations at top in respective class.
EXCEPTION: Invalid type in JSON write (TagMediaModel) I guess you are converting json to your custom class one or more times. Do it only once. It will resolve your problem.

Related

#import "Project-Swift.h" comes some strange issue

Project is mixed with oc and swift.
#import "myProjectName-Swift.h" in the AppDelegate.m,:
Project is Objective-c language created by me, and using almost swift language to write. and In the Appdelegate.m I want to use swift's class, and so
But unfortunate, my project occurs some error in myProjectName-Swift.h:
The code is below:
SWIFT_CLASS_PROPERTY(#property (nonatomic, class, readonly, copy)
NSString * _Nonnull ;)
+ (NSString * _Nonnull);
SWIFT_CLASS_PROPERTY(#property (nonatomic, class, readonly, copy)
NSString * _Nonnull ;)
+ (NSString * _Nonnull);
SWIFT_CLASS_PROPERTY(#property (nonatomic, class, readonly, strong) UIColor * _Nonnull APP_COLOR;)
+ (UIColor * _Nonnull)APP_COLOR;
The error are:
Expected ';' at end of declaration list.
cannot declare variable inside #interface or #protocal
Expected member name or ';' after declaration specifiers
Expected ']'
Property requires fields to be named
Missing '[' at start of message send expression
And so on...
Attension
And In the global swift, I set Chinese characters variable like this:
class Global: NSObject {
}
EDIT - 1
Because I think a error point out the static let "'s ,so I annotation this line, project will not show this error. Or I delete the ,`, will not show the error too.
Objective-C doesn't support Unicode in identifiers (variable names, class names, method names etc), only in string literals ("🏋"). Only a subset of ASCII is allowed (start with _[a-zA-Z], +[0-9] afterwards).
Example:
class MyClass : NSObject {
func 😞() { }
}
This will break when you compile it in a mixed project. Instead you need to give it a valid Objective-C name, like so:
class MyClass : NSObject {
#objc(unhappyFace)
func 😞() { }
}
which will compile (and you need to access it as unhappyFace on the ObjC side).
Or in your example you need to modify your Global object:
class Global: NSObject {
#objc(emptyNumberNotAllowed)
static let 手机号码不能为空 = "手机号码不能为空"
... etc ...
}

How to JSExport a Objective-C Method with Object

I want to write a method by the Objective-C that can be exported to JavaScript, so that I can get the JavaScript Object into the native code. For example in the following code: someObject is a native implemented object, and fun is its method.
someObject.fun({ k : 'value1', k2 : 'value2'})
I know that using JSExport can export the native method to JavaScript. and successfully pass the JavaScript String to the native code (NSString*). But when I want to pass the JavaScript Object to native, it fails.
How to solve this?
Thanks a lot
In addition to the conversion of javascript strings to NSString* as you have already observed, Javascript objects are copied to a KVC-compliant objective-C object (essentially, an NSDictionary instance) before being passed to your objective-c method.
For example, with the following definitions:
#protocol MyJSAPI
- (void)fun:(id)param;
#end
#interface MyObject: NSObject<MyJSAPI>
- (void)fun:(id)param;
#end
and the initialization of your JSContext as follows:
myjscontext[#"someObject"] = [[MyObject alloc] init];
[myjscontext evaluateScript:#"someObject.fun({ k : 'value1', k2 : 'value2'});
then your fun:(id)param method can access the k and k2 fields of the objects like this:
#implementation MyObject
- (void)fun:(id)param {
NSString* k = [param valueForKey:#"k"];
NSString* k2 = [param valueForKey:#"k2"];
NSLog(#"k = %#, k2 = %#", k, k2);
}
#end
In addition to ste3veh answer.
You can use JSExportAs macro in following way to export Objective-C method as JavaScript one:
#interface MyObject: NSObject <JSExport>
JSExportAs(fun,
- (void)fun:(id)param
);
#end
#implementation MyObject
- (void)fun:(id)param {
NSString* k = [param objectForKey:#"k"];
NSString* k2 = [param objectForKey:#"k2"];
NSLog(#"k = %#, k2 = %#", k, k2);
}
#end
In this case param would be implicitly converted to corresponding Objective-C oblect, using -[JSValue toObject]. In your case it will be converted in NSDictionary. To avoid implicit conversion, you may specify parameter as JSValue:
#interface MyObject: NSObject <JSExport>
JSExportAs(fun,
- (void)fun:(JSValue*)param
);
#end
#implementation MyObject
- (void)fun:(JSValue*)param {
NSString* k = [[param valueForProperty:#"k"] toString];
NSString* k2 = [[param valueForProperty:#"k2"] toString];
NSLog(#"k = %#, k2 = %#", k, k2);
}
#end
Note that big JavaScript objects, i.e. window or document, are very expensive to convert into corresponding Objective-C ones, so second way is preferred. Also, you can use JSValue parameter to call back JavaScript methods of this object from Objective-C, using callWithArguments:.
I don't think you can. See the JSExport.h header: It defines what the arguments can be, and it doesn't appear that generic JavaScript objects can be passed.

Protocol subclassing and conformance

Given
#protocol Response <NSObject>
#end
#protocol DataResponse <Response>
#end
#interface ListUsersResponse : NSObject <DataResponse>
#end
#interface RequestExecutor : NSObject
+(id<Response>) execute: (id<Request>) request receptor: (Class) model;
#end
ListUsersRequest * request = [self buildListUsersRequest];
ListUsersResponse * result = [RequestExecutor execute:request receptor:[ListUsersResponse class]];
I get an Initializing 'ListUsersResponse *__strong' with an expression of incompatible type 'id<Response>' error. Why is that? Cant the compiler detect protocol conformance? How to solve it?
These warning is because your RequestExecutor's execute: method returns an object of a general id<Response> type. The variables, however, are declared as ListUsersResponse * so the compiler expects a more specific type (and it isn't sure if that type cast is correct or not, it has no way of knowing).
You can get rid of the warning by either:
a) Declaring your variables with id<Response> type instead of ListUsersRequest * type like:
id<Response> result = [RequestExecutor execute:request receptor:[ListUsersResponse class]];
Or
b) Casting them on the fly (if you are sure that at that point they will be of the appropriate class):
ListUsersResponse *result = (ListUsersRequest *)[RequestExecutor execute:request receptor:[ListUsersResponse class]];

RestKit NSDictionary mapping NULL values

I have a mapped object which have this property:
#interface SynchObj : NSObject
#property (nonatomic, copy) NSDictionary *fields;
#end
mapped as
mappingDict = #{ #"fields" :#"fields",};
responseMapping = [RKObjectMapping mappingForClass:[SynchObj class]];
[responseMapping addAttributeMappingsFromDictionary:mappingDict];
But when the server send a dictionary like this
{
name:null
surname:null
}
the mapping produces a dictionary with these values:
name : "<null>"
surname : "<null>"
I would like to have "" instead of "". Is it possible?
You should be able to use KVC validation which RestKit supports to verify / edit the value before it is set. If you implement validateValue:forKey:error: on your destination class (SynchObj) you can verify and edit the value being set for any key (you would need to iterate the keys and values of the dictionary).

JSONModel: json to array?

Is it possible to parse json to an array of JSONModel objects using JSONModel? Like parse json below:
[{"id" : 1}, {"id" : 2}]
to two JSONModel objects having property of "id".
You should use arrayOfModelsFromDictionaries: on your model class like so:
NSArray* models = [YourModelClass arrayOfModelsFromDictionaries: objects];
This will go over "objects" and convert each dictionary to a model and you get the result in models. If any item in objects fail to convert to model "models" will be nil.
Here's the class docs for this method:
http://jsonmodel.com/docs/Classes/JSONModel.html#//api/name/arrayOfModelsFromDictionaries:
Why not trying BWJSONMatcher?
First you should declare your own data model:
#interface MyDataModel : NSObject
#property (nonatomic, assign) NSInteger id;
#end
Then you can easily get your array with BWJSONMatcher within one line:
NSArray *jsonArray = [BWJSONMatcher matchJSON:jsonString withClass:[MyDataModel class]];
Hope this could help you.

Resources