Ive been working with JSONModel, the tutorials are making sense. They are parsing JSON contain an array with multiple indexes.
I wanted to make sure JSONModel allowed to be used with say this dataset: https://gist.github.com/ryancoughlin/8043604
tide is not an array correct? But there is tide.tideSummary - which contains array of tide data across multiple days.
AllTide.h
#import "JSONModelLib.h"
#import "Tide.h"
#interface AllTide : JSONModel
#property (strong,nonatomic) NSDictionary<Tide> *tide;
#end
Tide.h
#import "JSONModelLib.h"
#import "TideSummaryStats.h"
#protocol Tide #end
#interface Tide : JSONModel
#property (nonatomic, strong) NSArray<TideSummaryStats> *tideSummaryStats;
#end
TideSummaryStats.h
#import "JSONModelLib.h"
#protocol TideSummaryStats #end
#interface TideSummaryStats : JSONModel
#property (nonatomic, strong) NSString *maxheight;
#property (nonatomic, strong) NSString *minheight;
#end
TideDetailViewController - Displays a single location (detail view) vs a list of multiple locations
#interface TideDetailViewController () {
AllTide *_objTide;
}
#end
#implementation TideDetailViewController
- (void)viewDidAppear:(BOOL)animated {
NSString *locationQueryURL = #"http://api.wunderground.com/api/xxxxx/tide/geolookup/q/43.5263,-70.4975.json";
//fetch the feed
_objTide = [[AllTide alloc] initFromURLWithString:locationQueryURL completion:^(JSONModel *model, JSONModelError *err) {
NSLog(#"Tides: %#", _objTide.tide);
}];
}
Been going through several JSONModel tutorials and it makes sense, I think I am having trouble where my JSON format differs from the tutorials. Again, where my tide does not return an array.
Would this be a good case to utilize JSONModel keymapper?
Any ideas? Let me know if I can provide anything else. Been diving around for some guidance, but a bit stuck. Thanks in advance!
you don't need AllTide.h
try this:
TideDetailViewController - Displays a single location (detail view) vs a list of multiple locations
#interface TideDetailViewController () {
NSArray *arrTide;
}
#end
#implementation TideDetailViewController
- (void)viewDidAppear:(BOOL)animated {
NSString *locationQueryURL = #"http://api.wunderground.com/api/xxxxx/tide/geolookup/q/43.5263,-70.4975.json";
//fetch the feed
[JSONHTTPClient getJSONFromURLWithString: locationQueryURL
completion:^(NSDictionary *json, JSONModelError *err) {
arrTide = [TideSummaryStats arrayOfModelsFromDictionaries:json[#"tide"][#"tideSummaryStats"] ];
NSLog(#"Tides: %#", arrTide[0]);
}];
}
Related
Now, I have a realm model , including images, audios and others. So I have to get the URLs of the media files and give the model value of the URLs. But I meet a problem that I cannot save them into the realm. Because I can not save NSArray , also when I use the RLMArray to contain them ,it also don't be solved. So how can I give my model the URLs?
Its not possilbe to directly add the NSURL type in Realm but you can use workaround on your own like :-
#interface MyModel : JOBIBaseModel
#property (nonatomic, strong) NSString * urlString;
-(NSURL *)getUrl;
#end
#implementation MyModel
-(NSURL *)getUrl{
return [NSURL URLWithString:self.urlString];
}
#end
Then access it from your object like:-
NSURL *url=Obj.getUrl;
Update for array
RLM_ARRAY_TYPE(MyArrayModel);
#interface MyArrayModel : JOBIBaseModel
#property (nonatomic, strong) NSString * urlString;
-(NSURL *)getUrl;
#end
#implementation MyArrayModel
-(NSURL *)getUrl{
return [NSURL URLWithString:self.urlString];
}
#end
#interface MyModel : JOBIBaseModel
#property (nonatomic, strong) RLMArray <MyArrayModel> * strings;
#end
#implementation MyModel
#end
And use it like:-
NSURL *url=Obj.strings[0].getUrl;
after many hour of tutorials and googling i knew that when we define a property inside the header file the compiler automatically generate the setters and getters here is an example:
"example.h"
#property(strong,nonatomic) NSNumber *test;
example.m
[self.test setTest [#"3"]];
so what i want is to access this method to check the method declaration and here is the reason that i want
Full Scenario
#interface exampleController ()
{
int example;
}
// here is a instance variable used to save a value while the app running i am getting this value from a dictionary and then save the value of the example variable to the core data
here is the entity class
exampleEntity.h
#property(strong,nonatomic) NSNumber *example;
exampleEntity.m
#dynamic example;
// since the instance variable is int we need to cast it to NSNumber so i follow this link
[entry setExample : [NSNumber numberWithInt:example]];
Finally after running this code i go into this exception:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException'
Full Code
#import "viewController.h"
#interface viewController ()
{
int example;
}
- (void)viewDidLoad {
gettingTheExampleValueFromDictionary();
}
-(void)gettingTheExampleValueFromDictionary()
{
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:requestHandler options:0 error:&jsonParsingError];
example = [[dictionary objectForKey:#"exampleId"] intValue];
}
- (IBAction)doneButton:(id)sender {
[self insertDataToCoreData];
[self dismissSelf];
}
-(void)insertDataToCoreData {
CoreData *coreDataStack = [CoreData defaultStack];
ExampleEntity *entry = [NSEntityDescription insertNewObjectForEntityForName:
#"ExampleEntity" inManagedObjectContext:coreDataStack.managedObjectContext];
[entry setExample :[NSNumber numberWithInt:example]];
// here we go into the error //
[coreDataStack saveContext];
}
#end
// and if you ask me for entity class here is:
#import <Foundation/Foundation.h>
#interface ReservationEntity : NSObject
#property (nonatomic,strong) NSNumber *example;
#end
#import "exampleEntity.h"
#implementation exampleEntity
#dynamic example;
#end
// and if you ask me for core data here is the pic needed //
// the configuration of xcdatamodel
In your case you should change:
#dynamic example;
to
#synthesize example;
or just delete the line of code #dynamic example.
Because #synthesize generates the getter&setter for the property, while #dynamic means the getter&setter are created in runtime(e.g. NSManagedObject's subclasses)
I have this simple model class that represent rss article called RSSEntry.
Now I want to start working wit core data with this model class, but I didn't create the project with the 'use core data' checkbox checked.
this is the class:
#import <Foundation/Foundation.h>
#interface FRSSEntry : NSObject{
NSString *_blogTitle;
NSString *_articleTitle;
NSString *_articleUrl;
NSDate *_articleDate;
NSString *_articleImageUrl;
NSString *_content;
}
#property (copy) NSString *blogTitle;
#property (copy) NSString *articleTitle;
#property (copy) NSString *articleUrl;
#property (copy) NSDate *articleDate;
#property (copy) NSString *articleImageUrl;
#property (copy) NSString *content;
- (id)initWithBlogTitle:(NSString*)blogTitle articleTitle:(NSString*)articleTitle articleUrl:(NSString*)articleUrl articleDate:(NSDate*)articleDate articleImageUrl:(NSString *)imageUrl andContent:(NSString *)content;
#end
the implementations is:
#import "FRSSEntry.h"
#implementation FRSSEntry
#synthesize blogTitle = _blogTitle;
#synthesize articleTitle = _articleTitle;
#synthesize articleUrl = _articleUrl;
#synthesize articleDate = _articleDate;
#synthesize articleImageUrl = _articleImageUrl;
#synthesize content = _content;
- (id)initWithBlogTitle:(NSString*)blogTitle articleTitle:(NSString*)articleTitle articleUrl:(NSString*)articleUrl articleDate:(NSDate*)articleDate articleImageUrl:(NSString *)imageUrl andContent:(NSString *)content
{
if ((self = [super init])) {
_blogTitle = [blogTitle copy];
_articleTitle = [articleTitle copy];
_articleUrl = [articleUrl copy];
_articleDate = [articleDate copy];
_articleImageUrl = [imageUrl copy];
_content = [content copy];
}
return self;
}
#end
very simple. Now how do I convert it so I can use it as a core data entity?
So to transform your model class into an NSManagedObject subclass you have to remove the instance variable declarations. Then replace all your #synthesize statements with #dynamic. This tells the compiler that CoreData will provide the implementation for those properties so it can do it's magic there. The custom initializer you have then also needs to be removed because NSManagedObject objects are initialized in a different way.
The code would look something like
#import <Foundation/Foundation.h>
#interface FRSSEntry : NSManagedObject
#property (copy) NSString *blogTitle;
#property (copy) NSString *articleTitle;
#property (copy) NSString *articleUrl;
#property (copy) NSDate *articleDate;
#property (copy) NSString *articleImageUrl;
#property (copy) NSString *content;
#end
-
#import "FRSSEntry.h"
#implementation FRSSEntry
#dynamic blogTitle;
#dynamic articleTitle;
#dynamic articleUrl;
#dynamic articleDate;
#dynamic articleImageUrl;
#dynamic content;
#end
You usually initialize them with something like
// Get the entity description
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"FRSSEntry" inManagedObjectContext:context];
// Insert a new YourModelObject into the context
ReceivedMessage *newMessage = [[FRSSEntry alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:context];
You could have a custom initializer but you would have to call [super initWithEntity:entityDescription insertIntoManagedObjectContext:context]. The initializer would get really long with all this parameters so I suggest you just set each property once you have the object initialized.
Judging from your response, you have just begun CoreData integration. Creating an NSManagedObject subclass is just a tip of the iceberg when working with core data. CoreData is a big an complex framework so I suggest you start by reading https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreData/cdProgrammingGuide.html. Stack Overflow is also full of questions and great answers on this topic.
Another thing I suggest you look into is MagicalRecord. It's a great library that makes some of the tedious tasks very simple: https://github.com/magicalpanda/MagicalRecord
Let us say I have an NSObject Class Person.
#interface Person : NSObject
#property NSString *id;
#property NSString *name;
#property Address *billingAddress;
#end
#interface Address : NSObject
#property NSString *lane;
#property NSString *country;
#property NSString *zip;
#end
Now when I fetch the response from a URL, the response is in the form:
{
"response":
{
"Persons":[{"id":"2232","name":"John","Address":{"lane":"Adelaide Avenue","country":"Canada","zip":"45503"}}{"id":"3422","name":"Jane","Address":{"lane":"Victoria Avenue","country":"Australia","zip":"34903"}}]
}
}
I want to parse the response directly into objects without having to write a method to read and assign objects from NSDictionary. Is there are no objects to parse directly from the response to Object based on the Object parameters similar to "GSon" in Android.
EDIT:
I have used the below code to have generic class that does the job for strings without having to know about the object itself.
for (NSString *key in [dct allKeys]) {
if ([cat respondsToSelector:NSSelectorFromString(key)]) {
[cat setValue:[dct valueForKey:key] forKey:key];
}
}
There is no such magic, not even in Android's GSon!!!
Some where down the line you need to write code for converting JSON to your object.
You may create a generic class, or a method (just once) to convert all dictionary values to your object.
After some digging I did get a JSON framework that does exactly what I wanted - JSONModel.
We just need to specify Models and relationships and all the logic for converting JSON response to the models is handled by the framework. Very handy.
Basic usage :
Consider you have a JSON response like
{"id":"10", "country":"Germany", "dialCode": 49, "isInEurope":true}
The corresponding model will be
#import "JSONModel.h"
#interface CountryModel : JSONMode
#property (assign, nonatomic) int id;
#property (strong, nonatomic) NSString* country;
#property (strong, nonatomic) NSString* dialCode;
#property (assign, nonatomic) BOOL isInEurope;
#end
We don't need to write additional code in the .m file to parse and assign values to the variables. Now to initialise the model from the response we just need to do the below
NSString* json = (fetch JSON here)
NSError* err = nil;
CountryModel* country = [[CountryModel alloc] initWithString:json error:&err];
The works well with complex data structures as well.
I'm new to iphone app development and I'm stuck on this problem I'm having with the app I'm trying to develop.
I have a datacontroller for populating a tableview. I created it using this tutorial:
About Creating Your Second iOS App
I'm trying to pass an array from one of my viewcontrollers that was created from a JSON response.
Here is some code from my viewcontroller.h that needs to pass the array:
#interface ViewController : UIViewController
#property (nonatomic, retain) DataController *Data;
#property (nonatomic, retain) NSMutableArray *array;
#end
viewcontroller.m:
#import "DataController.h"
[Data setMasterList: self.array];
DataController.h:
#interface DataController : NSObject
#property (nonatomic, strong) NSMutableArray *masterList;
- (void)setMasterList:(NSMutableArray *)newList;
#end
DataController.m
#import "LoginViewController.h"
- (void)setMasterList:(NSMutableArray *)newList {
if (_masterList != newList) {
_masterList = [newList mutableCopy];
NSLog("List: %#", newList);
}
}
The NSLog message never shows up in the console and the array is nil.
Any help is appreciated.
Thanks.
EDIT:
Here's the updated viewcontroller.m:
Data = [[DataController alloc] init];
[Data setMasterList: self.array];
The datacontroller.m:
- (void)setMasterList:(NSMutableArray *)newList {
if (_masterList != newList) {
_masterList = [newList mutableCopy];
NSLog("List: %#", self.masterList);
}
}
- (NSUInteger)countOfList {
NSLog("List: %#", self.masterList);
return [self.masterList count];
}
The first nslog inside setMasterList returns the correct array values, but the second nslog inside countOfList returns null. The list always returns null anywhere outside of setMasterList. Is it because I'm creating a new instance of the DataController? If so, how else could I pass the array to the datacontroller.
As in first comment Till have suggested, Data must be initialized before calling setMasterList. Such As:
Data = [[DataController alloc] init];
[Data setMasterList: self.array];