No automatic underscore ivar in Xcode 5.1.1 - ios

I just noticed that, for some reason, I don't seem to have automatically created underscore iVars in my iOS 7 project, and I wonder why that is. My setup:
MyClass.h
#property (readonly) NSNumber *aNumber;
MyClass.m
#interface MyClass ()
#property (readwrite, strong) NSNumber *aNumber;
#end
#implementation MyClass
(...)
- (NSNumber *)aNumber {
return _aNumber;
}
- (void)setANumber:(NSNumber *)aNumber {
_aNumber = aNumber;
}
#end
This results in Use of undeclared identifier: '_aNumber'.
Why is that so? I thought that underscore iVars are always automatically synthesized? Is it because of the class extension I use? If I put in #synthesize aNumber = _aNumber; it (obviously) works.

There is one exception to the automatic synthesize rule.
If you override both the getter and the setter of a property then you will have to manually synthesize the property.
This has been the case ever since auto synthesis came in.
Just add the #synthesize line and it will be fine.

Related

#dynamic property in Objective C

I'm trying to implement a Dynamic property in my project
This is my code.
MyClass.h
#interface MyClass : UIView
#property (strong, nonatomic) NSString *name;
#end
MyClass.m
#implementation MyClass
#dynamic name;
-(void)setName:(NSString *)name{
self.name = name;
}
#end
But when I run my app has crashed.
When I use an ivar had this error.
A property is just a bundle of two methods: a getter and a setter. So, when you write
#property (strong, nonatomic) NSString *name;
what you are really saying is
- (NSString *)name;
- (void)setName:(NSString *)name;
After that, each time the compiler encounters an expression of the form obj.name, it translates it to [obj name]. And each time you see a statement like obj.name = #"hello";, the compiler translates it to [obj setName:#"hello"].
The next thing is you have to make sure the property behaves properly. You have many options:
Write getters and setters manually, referring to an iVar
Synthesize getter and setter
Autosynthesize getter and setter
Write custom getters and setters
Use #dynamic to avoid compile time warnings, because you intend to do runtime magic. (Really, that's not what you want to do, because you need to understand the basics first.)
Write getters and setters manually, referring to an iVar
#interface MyClass : UIView {
NSString *_name;
}
#property (strong, nonatomic) NSString *name;
#end
and in the implementation
#implementation MyClass
- (NSString *)name {
return _name;
}
- (void)setName:(NSString *)name {
_name = name;
}
#end
Synthesize getter and setter
The last section is basically equivalent to this
#interface MyClass : UIView {
NSString *_name;
}
#property (strong, nonatomic) NSString *name;
#end
#implementation MyClass
#synthesize name = _name;
#end
Autosynthesize getter and setter
In practice, you would just use "autosynthetisation".
#interface MyClass : UIView
#property (strong, nonatomic) NSString *name;
#end
#implementation MyClass
#end
This means,
if you just declare a property
don't call #synthesize or #dynamic
don't implement any custom getter and setter
the code above will just create an iVar named _name and a getter and setter that looks exactly like the one in the first example.
This means that the the first two and this sections are equivalent, because they produce the same code.
Write custom getters and setters
This is what the term "dynamic property" really means. For example, you may want the name to be always uppercase. So you may write a property like this.
#interface MyClass : UIView {
NSString *_name;
}
#property (copy, nonatomic) NSString *name;
#end
#implementation MyClass
- (NSString *)name {
return _name;
}
- (void)setName:(NSString *)name {
_name = [name uppercaseString];
}
#end
(in the code above, I changed strong to copy - don't worry, this is just a comment anyways. And it's a true one, because the uppercaseString will never be the same, it will always be a copy of the original.)
This is maybe the only really interesting case! For example, this kind of property is what UIKit uses all the time, e.g. the text property of UILabel is a dynamic property like that. It doesn't just set some iVar, but it also makes sure that the visible text on the screen changes too.
#dynamic properties
they are really tricky to get right, and most of the time they are not worth the hassle IMHO.
Note: I simplified some things and left out details which are only detectable when using objc runtime inspection APIs
This StackOverflow answer: https://stackoverflow.com/a/1160545/7833793 does a good job of explaining what the differences between #synthesize and #dynamic are. Typically you use #dynamic if you're delegating the task of implementing the accessors (get, set). It seems to me like you would want to use #synthesize here. But with modern objective c, you shouldn't even need to specify and the iVar will be created for you automatically.
i.e.:
MyClass.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
#interface MyClass : NSObject
#property (strong, nonatomic) NSString *name;
#end
NS_ASSUME_NONNULL_END
MyClass.m
#import "MyClass.h"
#implementation MyClass
- (void)setName:(NSString *)name {
_name = name;
}
#end
Your solution leads to recursion, you are getting crash since you are not using ivar in setter, try this instead:
-(void)setName:(NSString *)name{
_name = name;
}

objective-C how to declare private property for category?

I'm new to objective-C, so apologies if this is repeated somewhere. I have a category(?) that is something like:
inside SomeClass.h:
#interface SomeClass (SomeCategory) <SomeDelegate>
#property (nonatomic, retain) id somePublicProperty;
#property (nonatomic, retain) id someProperty; // <-- i want to move this to "private"
#end
and now in my SomeClass.m, all i have is:
#implementation SomeClass (SomeCategory)
// dynamic setters/getters here for someProperty.
#end
I think the someProperty is public. how do i make this "private"? (in other words, how do i syntactically put this in the .m file? i tried to use
#interface SomeClass (SomeCategory) {
#property (nonatomic, retain) somePrivateProperty;
}
#end
but it just complains that i have duplicate definition of the category. how do i do this correctly?
In your .h file, you should not give the category. Just use:
#interface SomeClass : SomeBaseClass < SomeDelegate>
#property (nonatomic, retain) id somePublicProperty;
#end
In your .m file, define your private property inside a class extension:
#interface SomeClass ()
#property (nonatomic, retain) id somePrivateProperty;
#end
A class extension is not a like category in that it allows you to extend an interface as well as add new storage to your class.
In a class category, you can define new properties, but no storage will be allocated for it, so you have to do it by hand:
#interface SomeClass (SomeBaseCategory)
#property (nonatomic, retain) id somePrivateProperty;
#end
#implementation SomeClass {
id _somePrivateProperty;
}
- (void)setSomePrivateProperty:(id)property {
_somePrivateProperty = property;
}
- (id)somePrivateProperty {
return _somePrivateProperty;
}
#end
Otherwise your app will crash.
In any case, keep in mind that given the dynamic nature of Objective-C, your property will never be fully private, since you can always send a message to an Objective-C object through objc_msgsend and thus set or read the property value.
EDIT:
If you do not have the source code for a class implementation, you cannot define a class extension (as per source linked above).
In this case, you could use object association to define properties.
Just add the category definition in the .m file OUTSIDE the implementation block
Like so:
#interface MyClass (MyCategory)
#property (assign) BOOL myPrivateProperty;
#end
#implementation MyClass
...
#end
Categories are best used for adding capability to code you do not own and cannot change. Adding properties via categories is not impossible, but is much more difficult.
Class Extensions are best used for keeping properties your object needs, but are not intended to be public.
If you do truly need to add properties to this object, the way to do it is with the Objective-C runtime's associated objects
There's an excellent writeup of when/how to use them here

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);
}

What does this error mean: No declaration of property 'decisionText' found in the interface

I am having a label code for "decisionText" inside dot-m file as follows :
#synthesize decisionText ; //<<<This generates the error
inside dot-h file, the code is written as follows:
IBOutlet UILabel *decisionText
The error i get is :
No declaration of property 'decisionText found in the interface.
ps: In the interface builder when i click the label, i can find the name "decisionText" under Referencing Outlets mapped with File's Owner
Stuck on this. :(
As suggested I removed line #synthsize decisionText and used :
#property (nonatomic,weak) IBOutlet UILabel *decisionText ;
Now i get the error :
Expected a property attribute before 'weak'
Dot M file :
#import "ClickButtonViewController.h"
#implementation ClickButtonViewController;
//#synthesize decisionText ;
#property (weak,nonatomic) IBOutlet UILabel *decisionText ;
-(IBAction)buttonPressed:(id)sender
{
decisionText.text = #"Go for it!" ;
}
-(void)dealloc{
[decisionText release];
[super dealloc] ;
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
#end
in the .h file add:
#interface ViewController : UIViewController
{
//....
IBOutlet UILabel *decisionText ;
//...
}
#property (nonatomic, retain) IBOutlet UILabel *decisionText ;
//...
#end
then in the .m file add:
#synthesize decisionText ;
You use #synthesize statements with declared properties. Thus, your code should probably look like:
#interface ViewController : UIViewController
{
// your ivars go here
// but this is not needed:
//
// IBOutlet UILabel *decisionText;
}
// your properties go here
#property (nonatomic, retain) IBOutlet UILabel *decisionText;
#end
If you're using ARC, replace retain with weak.
And in your .m file, you would have:
#implementation ViewController
#synthesize decisionText = _decisionText;
// and your implementation goes here
Note:
While you can explicitly declare your instance variable, if you omit it, the #synthesize statement will create one for you. Thus, you don't need to explicitly declare any instance variable. In fact, I might argue that you should not explicitly declare your instance variable because if you have a typo, it only presents an opportunity to accidentally end up with two instance variables, the one you explicitly declared and the one the compiler will generate. I've seen that problem here on Stack Overflow more than once. So, in my example, I've omitted the explicit instance variable declaration and I'll let the compiler take care of it for me and it minimizes the chance for error.
While not required, it is often advised that #synthesize statements specify a different name for your property's instance variable (e.g., in this case, I'm suggesting that the property decisionText would have an instance variable of _decisionText). This helps discourage the accidentally reference to instance variables when you meant to invoke the property's getter or setter. (In fact, in Xcode 4.4 and later, if you omit the #synthesize statement, the compiler will automatically synthesize the instance variable for you with the leading underscore.) Thus, in your code, you would then refer to the property self.decisionText or to the instance variable _decisionText. It's generally not so critical for IBOutlet objects, but as you start to use your own custom properties, this convention becomes useful.
Alternatively, if you are using Xcode 4.4 you can use autosynthesis.
In which case you don't need to declare the iVar you can just write:
#property (weak, nonatomic) IBOutlet UILabel *decisionText;
And you don't need to write the #sythesize line at all.
If you do this - be aware that the generared iVar will have a leading underscore appended by default, although you should just stick to using the property accessor in this case so it makes little difference.
You can see what you can do in the Objective-C Features Availability Index
Change
IBOutlet UILabel *decisionText
to
#property (nonatomic, weak) IBOutlet UILabel *decisionText
You can only synthesize properties you defined like that with the #property keyword
You declared only the instance variable which will store the content of your property but you didn't declare the property itself. I think that the easiest way to solve that is to add in your public interface (.h file) or in your private interface (#interface ClassName () ... #end in ClassName.m file) the declaration of the property.
ClassName.h
#interface ClassName : ParentClass
#property (nonatomic, weak) IBOutlet UILabel decisionText; //This is the declaration of the property than you can ctrl-drag to wire it up to your label
#end
ClassName.m
#implementation ClassName
#synthesize decisionText = _decisionText //the _decisionText stuff is the name of the instance variable that will store the content of your property
... //your methods
#end

Difference in variable declarations in Cocoa Class

I'm new to iOS development and I've been seeing the following in several tutorials as well as when Xcode autogenerates code for me when subclassing one of my classes. Let's say I have the following .h and .m files
#import <UIKit/UIKit.h>
#interface Class : NSObject {
NSArray *_infos;
NSString *_context;
}
#property (nonatomic, retain) NSArray *infos;
#property (nonatomic, retain) NSString *context;
#end
#import "Class.h"
#implementation Class
#synthesize infos = _infos;
#synthesize context = _context;
#end
And then consider this which is how I would normally do it:
#import <UIKit/UIKit.h>
#interface Class : NSObject {
NSArray *infos;
NSString *context;
}
#property (nonatomic, retain) NSArray *infos;
#property (nonatomic, retain) NSString *context;
#end
#import "Class.h"
#implementation Class
#synthesize infos;
#synthesize context;
#end
What is the difference? From the notation I can just infer that they're just declaring the variables as private, but how does it work? If I'm correct.
It's a silly naming convention. Use it if you want to, leave it if you don't.
The advantage is that a method argument/local variable named context does not conflict with the ivar _context. It has little to do with privacy, since you can just specify #private to make the ivars private (or just #synthesize them in the first place).
The disadvantage is that you have underscores everywhere, and underscores are occasionally a bit special in C (though an underscore followed by a lowercase letter is only reserved in file scope, so you should be fine provided the ivar starts with a lowercase letter...). Where necessary, I stick an underscore at the end which feels less dirty.
Sidenote: A few people use method names beginning with an underscore to mean "private", but this convention is reserved by Apple.
The only difference is the name of the ivars ("instance variables") holding the properties.

Resources