Is the NSObject code below redundant? - ios

I am following the tutorial here: http://blog.soff.es/archiving-objective-c-objects-with-nscoding
to create an NSObject that can save my match data in a turn based game.
However I get this warning in my .m file:
Autosynthesized property 'title' will use synthesized instance variable '_title', not existing instance variable 'title'
So my Qustion is if (in the code below) I delete the code in between the brackets will I be losing something important?
#interface Note : NSObject <NSCoding> {
NSString *title;
NSString *author;
BOOL published;
}
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *author;
#property (nonatomic) BOOL published;
#end

You shouldn't explicitly declare ivars since the properties will auto-synthesize their own ivars with slightly different names. The explicit ivars are pointless and won't be used by the properties. Having them is just going to lead to bugs when you use your ivars by mistake when you meant to set a property.
The warning is pointing this out by letting you know there will be two similar ivars.
Your code should simply be:
#interface Note : NSObject <NSCoding>
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *author;
#property (nonatomic) BOOL published;
#end
This avoid bugs such as:
title = #"Some Title"; // sets your ivar, not the property
as opposed to:
_title = #"Some Title"; // directly sets the property's ivar
Of course you should use the property:
self.title = #"Some Title"; // uses the property methods

You would be losing instance variables, but you don't really want them as the properties will create them for you (with slightly different names) and it's safer to access these (kind of hidden) auto-generated instance variables via the property accessor methods.

Yes it is and likely you get something you do not want.
If you do not have an instance variable neither with the identifier identifier nor with the identifier _identifier, manual synthesize and automatic synthesize will create one with the name _identifier.
If you already have an instance variable with the identifier _identifier, manual synthesize and automatic synthesize will use it. (Therefore in most cases it is meaningless to declare such an instance variable.)
But if you have an instance variable with the identifier identifier (without underscore) manual synthesize will use it, while automatic synthesize will not use it and instead create a new one with the identifier _identifier. Therefore you have two instance variables identifier and _identifier. Typically you do not want this.

Related

Is declaring strong actually needed for Objective-C properties?

My understanding so far is that (retain) increases the reference count of a property and is essentially the exact same as (strong). Since all properties are set to retain by default (unless specified otherwise), is adding (strong) needed at all:
#property(nonatomic, strong) NSString *name;
Is the same as:
#property(nonatomic) NSString *name;
Both the above are the same, right?
Since ARC was introduced, "strong", "atomic", and "readwrite" are set by default.
These properties are equivalent:
#property NSArray *name;
#property (strong, atomic, readwrite) NSArray *name;
Source: http://useyourloaf.com/blog/default-property-attributes-with-arc.html
From the documentation:
By default, both Objective-C properties and variables maintain strong
references to their objects.
So both forms are the same.

Objective-C syntax; is it a class category?

I'm going through a tutorial on core-data in Objective-C and can't understand the following syntax:
#interface RootViewController : UITableViewController <CLLocationManagerDelegate> {
NSMutableArray *eventsArray;
NSManagedObjectContext *managedObjectContext;
CLLocationManager *locationManager;
UIBarButtonItem *addButton;
}
#property (nonatomic, retain) NSMutableArray *eventsArray;
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain) CLLocationManager *locationManager;
#property (nonatomic, retain) UIBarButtonItem *addButton;
#end
We have four properties here that are declared in the implementation file, which to my understanding means they are private. What exactly is happening within the curly brackets? Why are these variables put there? And also, is it a class extension? I see () are missing here so probably it is not. What is this kind of syntax called then?
Its not a category.Its just a class named RootViewController which extends UITableViewController and implements protocol CLLocationManagerDelegate.
Coming to your braces ->
generally if you don't create iVars in curly braces, by default they are created with underscore as prefix to them. This is done by compiler.
But here, you explicitly said, that the ivar should be without underscore(_).
Any you should synthesize them as below or else it will give a warning.
#synthesize eventsArray= eventsArray;
It's just a regular definition of a RootViewController class, the #interface doesn't necessarily have to be in a header file, private classes (that shouldn't/don't need to be accessible elsewhere) can also be defined directly in the .m file.
The definitions in the curly braces are just regular instance variables of the RootViewController class.
What you have is called the class interface. It is just the .h file of your program files. .If you want a class category, just do
#interface RootViewController (CategoryName)
and for an extension, inside the .m type
#interface RootViewController ()
#end
#implementation
Variables between curly braces:
{
NSMutableArray *eventsArray;
NSManagedObjectContext *managedObjectContext;
CLLocationManager *locationManager;
UIBarButtonItem *addButton;
}
are just usual variables.
For variable, defined with #property base word:
#property (nonatomic, retain) NSMutableArray *eventsArray;
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain) CLLocationManager *locationManager;
#property (nonatomic, retain) UIBarButtonItem *addButton;
created accessor and mutator methods. And also you can define options for those variables in bracers. Plus you can get local synonym for them, using base word #synthesize in .m file, like
#synthesize addButton = myLovelyButton;
then you can use myLovelyButton in .m file instead addButton
Both of these definition do not belong to the category.
For define category just type code like:
#interface <#className#> (<#categoryName#>)
{
//optional variables here
int i;
NSString *s;
}
//optional variables here
#property NSString *str;
//optional methods here
-(void)doSomething;
#end
Then you can implement your methods and use these variables:
#implementation <#className#> (<#categoryName#>)
-(void)doSomething
{
int i = 0;
str = #"blah";
s = #"wow";
NSLog(#"%i - %# - %#",i,str,s);
}
#end
Use that for add your methods to existing classes.
Variables inside brackets directly after the #interface or #implementation are instance variables. These are variables associated with each instance of your class, and thus accessible anywhere in your instance methods.
If you don't put the brackets, you declare global variables. Any variable declared outside of any bracket block will be a global variable, wether these variables are before or after the #implementation directive. And global variables are evil and needs to be avoided at all costs (you can declare global constants, but avoid global variables), especially because they are not thread-safe (and may thus generate bugs that are a mess to debug).
#interface YourClass : ParentClass
{
// Declare instance variables here
int ivar1;
}
// declare instance and class methods here, as well as properties (which are nothing more than getter/setter instance methods)
-(void)printIVar;
#end
// .m
int someGlobalVariable; // Global variable (bad idea!!)
#implementation YourClass
int someOtherGlobalVariable; // Still a bad idea
-(void)printIVar
{
NSLog(#"ivar = %d", ivar1); // you can access ivar1 because it is an instance variable
// Each instance of YourClass (created using [[YourClass alloc] init] will have its own value for ivar1
}
Only modern compilers let you declare instance variables (still in brackets) also inside either your class extension (#interface YourClass () in your .m implementation file) or in your #implementation, in addition to the possibility to declare them after the #interface in your .h. The benefits being to hide those instance variables from external users of your classes, by declaring them in the .m file and not in the .h file anymore, because users of your class don't need to be aware of the internal coding details of your class, but only needs to know the public API.
One final advice: instead of using instance variables, Apple more and more recommends to use #property directly, and let the compiler (explicitely using the #synthesize directive, or implicity with modern LLVM compilers) generate the internal backing variable. So that at the end you generally won't need to declare instance variables at all, and thus omit the empty { } after the #interface directive:
// .h
#interface YourClass : ParentClass
// Declare methods and properties here
#property(nonatomic, assign) int prop1;
-(void)printProp;
#end
// .m
#implementation YourClass
// #synthesize prop1; // That's even not needed with modern LLVM compiler
-(void)printProp
{
NSLog(#"ivar = %d", self.prop1);
}

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.

Add #propertys to Core Data class

I made few classes via Core Data. And I need some additional #propertys for one of that classes in runtime. This #propertys are responsible for download progress and I don't want to store them in Core Data DB. I tried to use a separate extension class:
#interface MyClass ()
{
CGFloat _downloadProgress;
NSInteger _downloadErrorCounter;
BOOL _downloadAllStuff;
BOOL _downloadUserCanceled;
}
#property (nonatomic, assign) CGFloat downloadProgress;
#property (nonatomic, assign) NSInteger downloadErrorCounter;
#property (nonatomic, assign) BOOL downloadAllStuff;
#property (nonatomic, assign) BOOL downloadUserCanceled;
#end
But private variables are not visible out of MyClass, and #propertys compile all right, but in runtime i get -[MyClass setDownloadErrorCounter:]: unrecognized selector sent to instance.
Can anyone suggest me some solution?
The easiest solution (if you don't want to modify the Xcode generated class files) is to add the properties to the Core Data model and define the
properties as transient. Transient properties are not saved to the store file.
Another option is to use a tool like "mogenerator", which generates two class files for each
entity, one for the Core Data properties (which is overwritten if the the model changes),
and one for your custom properties (which is not overwritten).
Update: Starting with Xcode 7, Xcode creates both a class and
a category for each managed object subclass, compare NSManagedObject subclass property in category. Custom properties can be added to the class
definition which is not overwritten when the model changes.
Just add
#synthesize downloadErrorCounter = _downloadErrorCounter;
...
in #implementation. Note, not #dynamic.
When trying to use the #synthesize solution i got the error:
#synthesize not allowed in a category's implementation.
Solution was to use associated objects as described in this blog: http://kaspermunck.github.io/2012/11/adding-properties-to-objective-c-categories/
MyManagedObject+Additions.h
#property (strong, nonatomic) NSString *test;
MyManagedObject+Additions.m
NSString const *key = #"my.very.unique.key";
- (void)setTest:(NSString *)test
{
objc_setAssociatedObject(self, &key, test, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *)test
{
return objc_getAssociatedObject(self, &key);
}

iOS 5.1: IBOutlet instance variables & #property declarations

While creating a custom iOS table view cell, I created a new .xib file, dragged/dropped some UI elements in interface builder and my .h file looked like this...
#import <UIKit/UIKit.h>
#interface MasterTableViewCell : UITableViewCell
{
IBOutlet UILabel *cellLabel;
IBOutlet UIImage *cellImage;
}
#property (nonatomic, retain) IBOutlet UILabel *cellLabel;
#property (nonatomic, retain) IBOutlet UIImage *cellImage;
#end
On some blogs I saw that the instance variables were missing. When do I need to declare instance variables? Are both instance variables and #property declarations not needed for a particular UI object.
Also I am creating the app using automatic reference counting, so garbage collection needs aren't there as well. What difference does that make in usage of instance variables & properties?
There is no garbage collection in iOS. iOS uses reference counting to track ownership of objects. Using ARC does not do away with reference counting, but the compiler takes care of releasing and retaining objects. When using ARC you are not allowed to send a retain, release, or autorelease message to an object, nor are you allowed to call [super dealloc] in a dealloc method. In your code above, since you are using ARC, the 'retain' attributes should be replaced by the 'strong' attribute.
When you use #property, and the corresponding #synthesize in your implementation, you do not need to create a backing instance variable - the compiler does that for you. #property along with #synthesize create your accessor methods (your getters and setters), and also enable you to use dot notation to refer to your objects' properties. You may still write your own accessor methods if you choose.
The above code could be replaced by the following:
#import <UIKit/UIKit.h>
#interface MasterTableViewCell : UITableViewCell
#property (nonatomic, strong) IBOutlet UILabel *cellLabel;
#property (nonatomic, strong) IBOutlet UIImage *cellImage;
#end
In your implementation file you would have:
#import "MasterTableViewCell.h"
#implementation MasterTableViewCell
#synthesize cellLabel;
#synthesize cellImage;
or
#synthesize cellLabel, cellImage;
... remainder of your code
In your code, to ensure that you are using your accessor methods, use 'self' to refer to your properties:
self.cellLabel.text = #"some text";
or
[[self cellLabel] setText:#"some text"];
I hope this helps clarify things a little.
If you don't create the instance variables (iVar's) then they will automatically be created for you if you are using the #synthesize directive (see below) so they really aren't required. If you are using #dynamic or writing your own methods and want to access the iVar directly then you need to declare it yourself.
In the documentation for Declared Properties under the Property Implementation Directives section, it states:
#synthesize You use the #synthesize directive to tell the compiler
that it should synthesize the setter and/or getter methods for a
property if you do not supply them within the #implementation block.
The #synthesize directive also synthesizes an appropriate instance
variable if it is not otherwise declared.
Note that this behavior is for "modern" runtimes (2.0 and newer). Before this, the iVar was required to be declared or the #synthesize would generate an error.

Resources