iOS JSONModel property which is correct - ios

if Data is
{ "id": "10", "country": "Germany", "dialCode": 49, "isInEurope": true }
someone using
#interface CountryModel : JSONModel
#property (assign, nonatomic) int id;
#property (strong, nonatomic) NSString* country;
#property (strong, nonatomic) NSString* dialCode;
#property (assign, nonatomic) BOOL isInEurope;
#end
other using
#interface CountryModel : JSONModel
#property (nonatomic) int id;
#property (nonatomic) NSString* country;
#property (nonatomic) NSString* dialCode;
#property (nonatomic) BOOL isInEurope;
#end
Which is better usage?

Both the methods are correct. Declaration of properties depends on your requirement.Properties are used to declare a class’s accessor methods. How can a class access model's data.While declaring property you can then optionally provide set of property attributes that define the storage semantics and other behaviors of the property.When we are defining an object's property as weak/strong we are defining its accessibility to the class.
It depends on how you need to access the data. If you want you object to thread safe,you can define as nonatomic. By defining it as strong/ assign it defines that you own the object.And by defining it as weak you dont own your object. Check this link for more info.
Hope it helps. Happy Coding!!

Related

Adding an object to NSMutableArray - weird behaviour

I am facing a very weird issue. I create an object and I add it to a NSMutableArray but when I try to read it after I insert it, some subclasses of the object change to some weird classes like
PINGIFAnimatedImageManager
Here is the code I use to create the object and insert it to the NSMutableArray:
CustomContentGridRow *row = [[CustomContentGridRow alloc]init];
row.child1 = [dataManager getMapLocation]; // This is the MapLocation object that will change to this weird PINGIFAnimatedImageManager
row.useFullWidth=1;
row.index=0;
[arrCustomChilds addObject:row];
This is the CustomContentGridRow class:
#interface CustomContentGridRow : NSObject
#property (nonatomic, assign) MapLocation *child1;
#property (nonatomic, assign) MapLocation *child2;
#property (nonatomic, assign) int useFullWidth;
#property (nonatomic, assign) int index;
#end
So when I put a breakpoint at this line [arrCustomChilds addObject:hotelRow];, when I read the row object I get the expected results. But when I place a breakpoint after the above code to read the arrCustomChilds the class of child1 changes to some weird classes. Also, sometimes it won't change to another class but it will give nil values.
Any idea why this is happening?
You should change property modifier from "assign" to "strong" for class objects. Otherwise undefined behaviour can happen.
In Xcode -> Product -> Scheme - edit Scheme. Check the settings of RUN mode. If it is Release change to Debug.
This will give you the correct values
Change below properties
#property (nonatomic, strong) MapLocation *child1;
#property (nonatomic, strong) MapLocation *child2;
assign to strong
Your interface should be:
#interface CustomContentGridRow : NSObject
#property (nonatomic, strong) MapLocation *child1;
#property (nonatomic, strong) MapLocation *child2;
#property (nonatomic, assign) int useFullWidth;
#property (nonatomic, assign) int index;
#end
the class objects should be strong not assign

accessing classes from another class in objective c

I have two classes.
GameData.h
#import "TeamData.h"
#property (assign, nonatomic) GameData* teamA;
TeamData.h
#interface TeamData : NSObject
#property (nonatomic, copy) NSString* teamName;
-(void) printTeamData;
A number of questions :
Inside GameData.m I have this code :
TeamData* team = self.teamA;
[team printTeamData];
The first line shows this warning :
Incompatible pointer types from TeamData* with an expression of type TeamData*
In another class, I am including GameData.h and I want to set the teamA name. How do I access that? So I want to fetch the teamA property from the GameData class and set its name property.
In GameData.h, your property points to its own class, not to TeamData
#property (assign, nonatomic) GameData* teamA;
assign is meant for primitive types such as BOOL or NSInteger.
The parent class should hold a strong reference to a child object.
So your property would be better off as
#property (strong, nonatomic) TeamData* teamA;
As for setting the teamA property, you would call setTeamA: on your GameData instance:
[myGameData setTeamA:...];

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;

Xcode requiring me to redeclare properties as instance variables

I have an object called SCPFAd and it is declared in its header file as follows:
#interface SCPFAd : NSObject
#property (strong, nonatomic) NSArray *imageURLs;
#property (strong, nonatomic) NSString *title;
#property (strong, nonatomic) NSString *price;
#property (strong, nonatomic) NSString *longDescription;
#property (strong, nonatomic) SCPFLocation *location;
#property (strong, nonatomic) SCPFCategory *category;
#property (strong, nonatomic) NSArray *properties;
#property (readonly, strong, nonatomic) NSString *sellerID;
#property (readonly, strong, nonatomic) NSString *timePosted;
- (id)initWithRawData:(NSDictionary *)rawData;
- (BOOL)displaysPrice;
#end
In the implementation file, I have an SCPFAd extension declared this way:
#interface SCPFAd ()
{
NSMutableDictionary *_rawData;
NSMutableArray *_imageURLs;
NSString *_title;
NSString *_price;
NSString *_longDescription;
SCPFLocation *_location;
SCPFCategory *_category;
NSMutableArray *_properties;
}
#property (strong, nonatomic) NSDictionary *rawData;
#property (strong, nonatomic) NSString *sellerID;
#property (strong, nonatomic) NSString *timePosted;
#property (strong, nonatomic) NSString *adID;
#end
I deliberately redeclared the properties rawData, imageURLs, and properties as instance variables because I want external objects to access or assign them as immutable types, but I'll be changing them internally.
What I don't understand is why, when I override the setters, I get a compiler error that says it can't find the variables _title, _price, _longDescription, _location, and _category. The error goes away when I redeclare title, price, longDescription, location, and category as above, but I see it as unnecessary--nothing in the class extension changes their external declarations.
This is how I'm overriding setTitle, for example:
- (void)setTitle:(NSString *)title
{
_title = title;
_rawData[#"name"] = title;
}
- (NSString *)title
{
if (!_title) {
_title = _rawData[#"name"];
}
return _title;
}
If I comment out NSString *_title; in the extension, the compiler says it can't find _title in the first line of the setter, and wherever it occurs in the getter. The getter used to work just fine, though, even without the redeclaration.
If you declare a property and then override both the getter and setter, it won't auto-synthesize the property. But you can just add a line to synthesize it to your implementation:
#synthesize title = _title;
As for having a property be an immutable type, and its backing instance variable be mutable, you're going to have an issue when from outside your class the immutable type is assigned to it, and you treat it as the mutable version, because it won't respond to the methods to mutate it. For example, you assign an NSArray to a variable, then try to treat it as an NSMutableArray, it won't work.
If you implement a getter, the compiler doesn't automatically create an ivar.
This is for a good reason. The property may (and, in my experience, usually is) created on request and returned, so in that case no instance variable is needed to store it and it would add a significant memory overhead to classes with a large number of such properties if every getter had an associated ivar.
One other comment. This:
NSMutableDictionary *_rawData;
// ...
#property (strong, nonatomic) NSDictionary *rawData;
May cause you problems. If rawData is set with an immutable dictionary, it will raise an exception when you attempt to mutate it later. Make sure you copy it on assign using -mutableCopy. (I assume you aren't copying it because it's marked strong, not copy. If you are, it's fine)
When you override the setter and getter (not just the getter), Xcode assumes you want complete control and doesn't create the backing store (the _title). You have to do it yourself with
#synthesize title = _title
If you implement a getter and a setter for a read-write property, or a getter for a read-only property then Clang (Xcode) will not synthesise the backing instance variable - see Apple's Encapuslating Data, note in the section You Can Implement Custom Accessor Methods.
You are implementing both the setter and the getter so you must provide your own instance variable if needed.

Access private interface property by public method

I would like to ask you some opinion about what I'm doing. I know it works, but I'm not sure is proper to do what I'm doing.
I have a superclass Building that need to expose two NSString, name and description. No one should be able to modify those variables apart their subclasses.
To get this result I have created two public method on the base class:
#interface Building : NSObject
- (NSString *)name;
- (NSString *)description;
#end
Then on each subclass I'm creating a private interface with name and description properties and let the magic happen.
#interface Barrack()
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSString *description;
#end
#implementation Barrack
#synthesize name, description;
...
#end
What you guys think about this?Is this a proper way to get this kind of result, anyone have better ideas about this topic?
Thanks for your opinion.
Best,
Enrico
Declare readonly properties in the interface, readwrite in the implementation class extension. No need for #synthesize. This is one of the main reason class extensions were added to Objective-C.
in Building.h
#interface Building : NSObject
#property (nonatomic, strong, readonly) NSString *name;
#property (nonatomic, strong, readonly) NSString *description;
#end
In Barrack.m
#interface Barrack ()
#property (nonatomic, strong, readwrite) NSString *name;
#property (nonatomic, strong, readwrite) NSString *description;
#end
#implementation Barrack
...
#end

Resources