accessing classes from another class in objective c - ios

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:...];

Related

iOS JSONModel property which is correct

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!!

Objective-C replace a property at runtime

Can I replace an property with new one using some obj-c runtime features.
So I have a class A which contains a property:
#property (nonatomic, strong) Status *status;
So I want to inherit from this class like ClassB : ClassA and have ability to switch original #property (nonatomic, strong) Status *status; to my new property like #property (nonatomic, assign) NSInteger status;
So the reasone why I needed because I don't want to have a full copy of class A which contains 20 properties, so I just want to inherit from it and replace one with needed type.
Not sure if this possible, but I know something like swizzling and some obj-c runtime features can make a magic in the code.

Objective C Semi Readonly property

I want to declare a public NSString property in my class which acts as a readonly property outside my class but i can assign any value to it inside my class. How can i achieve this behavior.
You have to declare your property in the .h file like this
#interface MyClass : NSObject
#property (strong, nonatomic, readonly) NSString *aString;
#end
but in your .m file you have to have
#interface MyClass () // your anonymous category
#property (strong, nonatomic, readwrite) NSString *aString;
#end
#implementation MyClass
#end
Externally the aString is readonly and internally you can set the value (readwrite).
You are achieving it by implementing a anonymous category also known as class extension in Objective-C
Define the property as readonly in the header and declare it readWrite in the implementation file in a class extension. The property will be readonly outside the classs implementation and read/write in the implementation.
// Interface file:
#interface Test : NSObject
#property (nonatomic, copy, readonly) NSString *propertyString;
#end
// Implementation file:
#interface Test () // Class Extension
#property (nonatomic, copy, readwrite) NSString *propertyString;
#end
#implementation Test
#end
See: Use Class Extensions to Hide Private Information
As #Amin Negm-Awad points out in an answer: the interface and class extension do not need to be in an interface or implementation file albeit this is the usual usage.
In .h file add:
#property(nonatomic,readonly)NSString* property;
In .m file add:
#interface yourClass ()
#property(nonatomic,readwrite)NSString* property;
#end
Define the property as readonly in your header file (interface), and as readwrite in your implementation file. That also allows you easily to make it weak / strong / copy.
This might be quit obvious:
in your .h file declare property as readonly
#property (nonatomic, assign, readonly, getter = isLoading) BOOL loading;
in your .m file declare property as readwrite
#property (nonatomic, assign, readwrite, getter = isLoading) BOOL loading;
This is an example, obviously you should create strong NSString property, and I assume compiler won't allow to set other value outside the class, but inside it will.
Beside the existing answers that told you to define a readonly property and change it to a readwrite property, which is completely correct and the intended pattern (that is, what readwrite is for), I want to add an probably important information:
You put the readonly definition in the interface. (Not header!)
You put the readwrite definition in a class continuation. (Not implementation file)
One might say that this is the same, because interfaces reside in the header and class continuations reside in the implementation file. But this is only the usual case.
You can additionally put class continuations in a third file. Then something like a "friend class" can import it additionally and this "fried class" has write access. I do that very often, when developing frameworks.
MyClass.h: // public header, available for everybody
#interface MyClass : NSObject
#property (readonly, …) id property1; // Everyone can read it
#property (readonly, …) id property2; // Everyone can read it
- (void)method; // Everyone can use it
#end
MyClass_Package.h: // project header, available for framework classes, unavailable for the user of the framework
#interface MyClass()
#property (readwrite, …) id property1; // All classes inside the framework can write it
- (void)packageMethod; // All classes inside the framework can use it
#end
MyClass.m
#interface MyClass() // A second class extension inside .m
#property (readwrite, …) id property2; // Only MyClass can write it
- (void)privateMethod; // Only MyClass can use it
#end
Define the property as readonly in the header, and set it using the underscore syntax.
#property (nonatomic, readonly) NSString *myString;
- (void)someMethodInYourDotMFile {
_myString = YES;
}

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.

Property attribute in continuation class does not match the primary class

In MyClass.h, I do:
#property (weak, nonatomic, readonly) CustomGridView *gridView;
and In MyClass.m, I do:
#property (weak, nonatomic, assign) CustomGridView *gridView;
However, I am getting a warning:
Property attribute in continuation class does not match the primary class
Can somebody tell me what I am missing here and how to silence the compiler?
It should be:
#property (weak, nonatomic, readwrite) CustomGridView *gridView;
You can't have weak and assign in the same property as they are both trying to specify the write type. What you have missed is the read/write access capability.
why do you need to duplicate Instance in .h and .m files ?
if you want to make your instance (gridView) readonly and need to access to instance (gridView) inside .m file you just need to override setGridView:(CustomGridView *) method for your instance (gridView) that's all.

Resources