jsonmodel - Model cascading (models including other models) - ios

I'm using the same example on the web
OrderModel.h
#protocol ProductModel
#end
#interface ProductModel : JSONModel
#property (assign, nonatomic) int id;
#property (strong, nonatomic) NSString* name;
#property (assign, nonatomic) float price;
#end
#implementation ProductModel
#end
#interface OrderModel : JSONModel
#property (assign, nonatomic) int order_id;
#property (assign, nonatomic) float total_price;
#property (strong, nonatomic) NSArray<ProductModel>* products;
#end
#implementation OrderModel
#end
But when I build the project I face one issue "Duplicate symbols"
duplicate symbol _OBJC_CLASS_$_OrderModel
ld: 576 duplicate symbols for architecture arm64
clang: error: linker command failed with exit code 1

The #implementation should be present in a .m file and the #interface in a .h file.
You should only import the .h file. Otherwise you will have multiple implementations for the same class.
ProductModel.h:
#interface ProductModel : JSONModel
#property (assign, nonatomic) int id;
#property (strong, nonatomic) NSString* name;
#property (assign, nonatomic) float price;
#end
ProductModel.m:
#import "ProductModel.h"
#implementation ProductModel
#end
OrderModel.h:
#interface OrderModel : JSONModel
#property (assign, nonatomic) int order_id;
#property (assign, nonatomic) float total_price;
#property (strong, nonatomic) NSArray<ProductModel>* products;
#end
OrderModel.m
#import "OrderModel.h"
#implementation OrderModel
#end
If you would want to use the ProductModel class in a View Controller for example just import the "ProductModel.h":
#import "ProductModel.h"

Related

Best practices for JSONModel and polymorphism

How do you deal with subclassing collection attributes in JSONModel?
Let's say I have these two endpoints with different responses of the same "product object".
domain.com/api/1.0/getProductList
domain.com/api/1.0/getProductDetails/productId
I wrote some example code below to show you my issue:
// ProductListModel
#interface ProductListModel : JSONModel
#property (nonatomic, strong) NSNumber *productId;
#property (nonatomic, strong) NSNumber *userId;
#property (nonatomic, strong) NSArray<OrderListModel> *orders;
#end
// ProductDetailModel
#interface ProductDetailModel : ProductListModel
#property (nonatomic, strong) NSURL *productImageUrl;
#property (nonatomic, strong) NSArray<OrderDetailModel> *orders;
#end
// OrderListModel
#protocol OrderListModel <NSObject>
#end
#interface OrderListModel : JSONModel
#property (nonatomic, strong) NSNumber *orderId;
#property (nonatomic, strong) NSNumber *price;
#end
// OrderDetailModel
#protocol OrderDetailModel <NSObject>
#end
#interface OrderDetailModel : OrderListModel
#property (nonatomic, strong) NSURL *orderImageUrl;
#end
The ProductDetailModel wants the same inherited attributes as ProductListModel, but it wants the orders array in the subclassed type.
However this leads to a compiler warning:
Property type 'NSArray<OrderDetailModel> *' is incompatible with type
'NSArray<OrderListModel> *' inherited from 'ProductListModel'
I found this related SO post but I'd rather not monkey patch the JSONModel library.
Edit #1:
This has been discussed in the #574, and #229 github issues before but requires a "type" string to determine what class to instantiate. This requires a change on the backend API.
Is there a way to do this without changing the backend API?
You can't override the property in the subclass to have a different type as it will violate the Liskov substitution principle - #Paulw11
For future readers, here's how the updated example code would look like:
// ProductBaseModel
#interface ProductBaseModel : JSONModel
#property (nonatomic, strong) NSNumber *productId;
#property (nonatomic, strong) NSNumber *userId;
#end
// ProductListModel
#interface ProductListModel : ProductBaseModel
#property (nonatomic, strong) NSArray<OrderListModel> *orders;
#end
// ProductDetailModel
#interface ProductDetailModel : ProductBaseModel
#property (nonatomic, strong) NSURL *productImageUrl;
#property (nonatomic, strong) NSArray<OrderDetailModel> *orders;
#end
// OrderListModel
#protocol OrderListModel <NSObject>
#end
#interface OrderListModel : JSONModel
#property (nonatomic, strong) NSNumber *orderId;
#property (nonatomic, strong) NSNumber *price;
#end
// OrderDetailModel
#protocol OrderDetailModel <NSObject>
#end
#interface OrderDetailModel : OrderListModel
#property (nonatomic, strong) NSURL *orderImageUrl;
#end

JSONModel NSString Issue

in my app i use Yahoo Api and get responce i currently use JSONModel in this create a json JSONModel class.
Past_Match.h file Like
#import <JSONModel/JSONModel.h>
#protocol squadModel #end
#interface squadModel : JSONModel
#property (assign, nonatomic) int i;
#property (strong, nonatomic) NSString *full;
#end
#interface logoModel : JSONModel
#property (strong, nonatomic) NSString *std;
#end
#protocol teamsModel #end
#interface teamsModel : JSONModel
#property (assign, nonatomic) int i;
#property (strong, nonatomic) NSString *fn;
#property (strong, nonatomic) NSString *sn;
#property (strong, nonatomic) logoModel *logo;
#property (strong, nonatomic) NSArray<squadModel> *squad;
#end
#interface aModel : JSONModel
#property (assign, nonatomic) int i;
#property (assign, nonatomic) int r;
#property (assign, nonatomic) int o;
#property (assign, nonatomic) int w;
#property (assign, nonatomic) int cr;
#end
#interface sModel : JSONModel
#property (strong, nonatomic) aModel *a;
#end
#protocol tModel #end
#interface tModel : JSONModel
#property (assign, nonatomic) int i;
#property (assign, nonatomic) int a;
//#property (strong, nonatomic) NSString *c;
//#property (strong, nonatomic) NSString *dt;
#property (assign, nonatomic) int fd;
#property (assign, nonatomic) int bd;
//#property (strong, nonatomic) NSString *cb;
#property (assign, nonatomic) int b;
#property (assign, nonatomic) int r;
#property (assign, nonatomic) int sr;
#property (assign, nonatomic) int six;
#property (assign, nonatomic) int four;
#end
#interface anewModel : JSONModel
#property (strong, nonatomic) NSArray<tModel> *t;
#end
#interface dModel : JSONModel
#property (strong, nonatomic) anewModel *a;
#end
#protocol past_ingsModel #end
#interface past_ingsModel : JSONModel
#property (strong, nonatomic) sModel *s;
#property (strong, nonatomic) dModel *d;
#end
#interface ScorecardModel : JSONModel
#property (strong, nonatomic) NSString *mid;
#property (strong, nonatomic) NSArray<teamsModel> *teams;
#property (strong, nonatomic) NSArray<past_ingsModel> *past_ings;
#end
#interface resultsModel : JSONModel
#property (strong, nonatomic) ScorecardModel *Scorecard;
#end
#interface queryModel : JSONModel
#property (strong, nonatomic) resultsModel *results;
#end
#interface Past_Match : JSONModel
#property (strong, nonatomic) queryModel *query;
#end
Past_Match.m file Like
#import "Past_Match.h"
#implementation squadModel
#end
#implementation logoModel
#end
#implementation teamsModel
#end
#implementation aModel
#end
#implementation sModel
#end
#implementation tModel
#end
#implementation anewModel
#end
#implementation dModel
#end
#implementation past_ingsModel
#end
#implementation ScorecardModel
#end
#implementation resultsModel
#end
#implementation queryModel
#end
#implementation Past_Match
#end
in the tModel i have issue if i remove // and try to get NSString of c,dt,cd object than my Past_Match object become Null. that all 3 NSString has a same issue i can't get that value. all other value is getting. what i missing something? Thanks in Advance..
This error may occurred due to the optional values in your response object try this.... It may works
#property (strong, nonatomic)NSString<Optional> *c;
#property (strong, nonatomic) NSString<Optional> *dt;
#property (strong, nonatomic) NSString<Optional> *cb;
Tip: Please made all properties to Optional

JSONModel library / model collection wrong

I'm using JSONMODEl (https://github.com/icanzilb/JSONModel) to parse a wordpress JSON FEED (with json-api).
Everything go's well except if I want the "comments".
my feed is like that :
comments = (
{
content = "<p>My comment</p>\n";
date = "2014-08-29 20:56:29";
id = 97813;
name = johndoe;
parent = 0;
url = "http://www.google.com";
}
);
so I try to make my "newsmodel" like that :
#import "JSONModel.h"
#import "commentmodel.h"
#protocol NewsModel #end
#interface NewsModel : JSONModel
#property (strong, nonatomic) NSString* title;
#property (strong, nonatomic) NSString* content;
#property (strong, nonatomic) NSString* thumbnail_images;
#property (strong, nonatomic) NSString* premium;
#property (strong, nonatomic) NSString* id;
#property (strong, nonatomic) CommentModel* comments;
#end
and my commentmodel like that
#import "JSONModel.h"
#interface CommentModel : JSONModel
#property (assign, nonatomic) int id;
#property (strong, nonatomic) NSString* name;
#property (assign, nonatomic) NSString* content;
#end
But When I try to build my app, my "feed" is empty.
if I comment the "comment" part of the news model, I got the content....
I think I'm stuck somewhere, but where ! If someone ave an idea :)
Many thanks
comments is an array, not a single comment, notice the top level ( and ) which designate an array in a NSDictionary NSLog(). Inside of the is an array element designated by { and }.
But the NewsModel has comments defined as a single comment (CommentModel), not an array. it should probably be declared:
In the docs see Model collections and how products is handled.
You will have to declare a protocol, see the example protocol at the top of the "Model collections" examples.
#protocol CommentModel
#end
Above:
#interface CommentModel : JSONModel
#property (strong, nonatomic) NSArray< CommentModel >* comments;
#protocol CommentModel
#end
#interface CommentModel : JSONModel
#property (assign, nonatomic) int id;
#property (strong, nonatomic) NSString* name;
#property (assign, nonatomic) NSString* content;
#end
#interface NewsModel : JSONModel
#property (strong, nonatomic) NSString* title;
#property (strong, nonatomic) NSString* content;
#property (strong, nonatomic) NSString* thumbnail_images;
#property (strong, nonatomic) NSString* premium;
#property (strong, nonatomic) NSString* id; //int?
#property (strong, nonatomic) NSArray<CommentModel>* comments;
#end
Thanks, got it to build, but now If i try to alloc it with
#try {
_feed = [[NewsFeed alloc] initWithDictionary:obj error:nil];
}
#catch (NSException *e) {
NSLog(#"Parse error : %# reason %#", [e name], [e reason]);
}
I got a Bad property protocol declaration reason is not allowed JSONModel property protocol, and not a JSONModel class.
my news feed is like that
#interface NewsFeed : JSONModel
#property (nonatomic, strong) NSArray <NewsModel> *posts;
#end
And work like a charme without the "comment" part...
Thanks
As an addition to the answers above, since I can't add a comment yet, all you have to do, is add an empty protocol with the same name, like this:
#protocol CommentModel
#end
Then, as noted here JsonModel documentation, notation would be different than a notation. The first one is a protocol declaration needed for JsonModel to work, the other one is an objc compiler helper declaration. You can combine them as noted in the same example:
#property (nonatomic) NSArray<ProductModel *> <ProductModel> *products;

JSONModel with data from several JSON sources

I have a fairly basic problem with the JSONModel. Let's say I have the following JSON:
{"items": [
{
"id": 1,
"title": "Bla",
"category": 1
}
]}
and this one:
{"categories": [
{
"id": 1,
"name": "Category"
}
]}
Now the easiest thing would be to put the categories inside the items and have JSONModel just use that. But there might be hundreds of items which share just a few categories, and the categories have several attributes like description, URLs and stuff, and that would blow up the items JSON.
How would I combine them in the best way using JSONModel (or might another library be better)?
My models currently look like this:
#interface Item : JSONModel
#property (assign, nonatomic) int id;
#property (strong, nonatomic) NSString* title;
#property (strong, nonatomic) Category* category;
#end
#interface Category : JSONModel
#property (assign, nonatomic) int id;
#property (strong, nonatomic) NSString* name;
#end
try this
#protocol Item
#end
#interface Item : JSONModel
#property (assign, nonatomic) int id;
#property (strong, nonatomic) NSString* title;
#property (strong, nonatomic) Category* category;
#end
#interface Items : JSONModel
#property (strong, nonatomic) NSArray<Item> *items;
#end
#protocol Category
#end
#interface Category : JSONModel
#property (assign, nonatomic) int id;
#property (strong, nonatomic) NSString *name;
#end
#interface Categories : JSONModel
#property (strong, nonatomic) NSArray<Category> *categories;
#end
Your JSON is array of items or categories

Weird unknown type name issue

So I have this -
#import <UIKit/UIKit.h>
#import "RateView.h"
#interface BasicCardViewController : UIViewController<RateViewDelegate>
#property (weak, nonatomic) IBOutlet UILabel *label;
#property(copy, nonatomic)NSString *message;
#property(atomic)NSInteger rating;
#property (strong, nonatomic) IBOutlet RateView *rateView;
#property (weak, nonatomic) IBOutlet UILabel *ratingLabel;
#end
and this - in my RateView.h file.
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#class RateView;
#protocol RateViewDelegate
-(void)rateView:(RateView *)rateView ratingDidChange:(float)rating;
#end
#interface RateView : UIView
#property(strong,nonatomic)UIImage* fullSelectedStar;
#property(strong,nonatomic)UIImage* notSelectedStar;
#property(strong, nonatomic)UIImage* halfSelectedStar;
#property (assign, nonatomic)float rating;
#property(assign) BOOL editable;
#property (strong) NSMutableArray* imageViews;
#property(assign,nonatomic) int maxRating;
#property(assign) int midMargin;
#property(assign)int leftMargin;
#property (assign) CGSize minImageSize;
#property (assign) id <RateViewDelegate> delegate;
#end
But I get two errors -
1.Cannot find protocol declaration for 'TooviaRateViewDelegate'
2.Unknown type name "RateView"
I've tried to clean, and I've verified that the files are where they should be (their filepaths are to the project).
Why is this happening?
Edit - my AppDelegate.h
#import <UIKit/UIKit.h>
#import "SearchViewController.h"
#interface TooviaAppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property NSOperationQueue *queue;
#property (strong, nonatomic) NSDictionary *userProfile;
#property (strong, nonatomic) SearchViewController *searchViewController;
- (NSOperationQueue*) getOperationQueue;
- (id)getSettings:(NSString *)keyPath;
- (void) saveCookies;
#end
There are also issues in my SearchViewController
#import <UIKit/UIKit.h>
#import "BasicCardViewController.h"
#interface SearchViewController : UIViewController
<UISearchBarDelegate, UISearchDisplayDelegate, UITableViewDataSource, UITableViewDelegate>
- (IBAction)searchButtonClicked:(UIButton *)sender;
- (IBAction)backgroundTap:(id)sender;
#property (weak, nonatomic) IBOutlet UITableView *resultTable;
#property (weak, nonatomic) IBOutlet UITextField *searchBar;
#property (strong, nonatomic) NSArray *resultsTuples;
#property (weak, nonatomic) IBOutlet UIButton *searchButton;
#property (copy, nonatomic) NSArray *controllers;
#property(strong,nonatomic)BasicCardViewController *detailController;
Delegate and data source properties are usually marked as weak for the object graph management reasons described earlier, in “Avoid Strong Reference Cycles.”

Resources