The declared property issue in Objective-C - objective-c

My xcode version is 4.2.
When I use property to generate getter/setter methods.
Here is the code:
#interface NewSolutionViewController : UIViewController
#property(nonatomic, weak) NSString a;
There is no issue exist. However when I turn into basic data type
#interface NewSolutionViewController : UIViewController
#property(nonatomic, weak) int a;
My program crashed. Do you guys know the reason?

A basic data type is not an object, and hence does not need to be declared weak.
Use
#property (nonatomic, assign) int a;
to directly assign to the variable.

The problem is that an int is not an NSObject.
Elaborating a bit...
NSObject is the root class of most Objective-C class hierarchies. Read up on Apple's Objects, Classes, and Messaging tutorial.
int is a basic machine type. It doesn't have methods, like an object, so it doesn't respond to messages.

int doesn't respond to retain - you probably want to put an assign in the property declaration for that one.

Related

Properties vs. Instance Variables

I am confused as to why some classes declare a property but do not declare an ivar and vice versa.
Is it standard practice when declaring an instance variable to also declare it as a property as well?
Example:
#interface AppDelegate : NSObject <UIApplicationDelegate>
{
UIWindow *window;
UINavigationController *navigationController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
is just standard practice when declaring a class's ivar to make it a property as well?
I get that the #property creates its own elongated setter (and getter with #synethesize) but why does it need to be an ivar as well?
It doesn't.
In the old days, ivars were required to be declared in the #interface. This is actually still true for PPC and i386 (i.e. 32-bit intel) targets. This is because of the fragile base class problem, which required that all subclasses know the exact size of their superclass. As such, ivars need to be in the #interface or nobody can subclass the class.
With the move to x86_64 and ARM, alongside obj-c 2.0 came a fix for the fragile base class problem. With this fix, class sizes no longer need to be known at compile time but can be deferred to runtime. Therefore, ivars can be declared in other places. Notably, an ivar can now be synthesized from a #property (more specifically the #synthesize line in the implementation). In Clang they can also be declared in a class extension block (which looks like #interface ClassName ()) or directly on the #implementation.
Today, there are 3 reasons why you find ivars declared in #interface blocks:
Old code (or programmers with old habits) that hasn't been updated to take advantage of the ability to hide ivar declarations.
Code that needs to run on PPC or i386.
Code that, for whatever reason, wants their ivars to be public. This should never be the case.
When writing code today that doesn't need to target the old runtime, you should either synthesize your ivars from your properties (preferred), or if you need ivars that aren't tied to properties you should declare them in a class extension or on your #implementation. The primary reason for this is because the header file documents the public API of your class and should not contain anything that's not public. Ivars are not public, and therefore should not be in the header file.

Objective C - Defining an instance variable when defining a property

I saw this code snippet on the Internet (http://iphonedevelopment.blogspot.com/2008/12/outlets-property-vs-instance-variable.html):
#import <UIKit/UIKit.h>
#interface MyViewController : UIViewController {
UILabel *myLabel;
}
#property (nonatomic, retain) IBOutlet UILabel *myLabel;
#end
My question is...When #synthesize is called isn't the UILabel instance variable created automatically? What is the point of creating the instance variable in the header file.. Can you get away with just the #property?
When #synthesize is called isn't the UILabel instance variable created automatically?
Yes.
What is the point of creating the instance variable in the header file.
Personal preference. Some developers (like me) prefer to see a complete picture of the state of a class. It helps to see what instance variables are available, as well as check that all instance variables are released correctly.
It's also a relatively new feature. Older code wouldn't expect automatically-generated instance variables.
Can you get away with just the #property?
No, you need to #synthesize to get an automatically generated instance variables A property value that's generated programmatically would not map directly to any instance variable.
#synthesize will create the instance variable but you will not be able to see it in the debugger which can be downright inconvenient.
Consider filing a bug with Apple about this.
Yes you can get away with just the #property in Objective-c 2.0.
see: Do declared properties require a corresponding instance variable?

What is the difference between IBOutlet as a property or as a variable?

There are two different methods to declare IBOutlet.
In #interface section as variable:
IBOutlet UIButton *exampleButton;
Below the curve bracket but before #end of .h file as property:
#property (nonatomic, retain) IBOutlet UIButton *exampleButton;
What is the difference between these two methods and where should I use each one? Which method is better and in what cases?
Either one works fine in my experience. What doesn't work is declaring both the instance variable and the property "IBOutlet" -- that seems to really confuse things. If for some reason you want to avoid providing public access to your outlet, you can declare it as an instance variable and simply not create the property. On the other hand, now that the runtime will synthesize instance variables for you, many people are declaring only properties and skipping the explicit instance variable declaration; in that case, you'd obviously declare the property as the IBOutlet.
The #property combined with #synthesize setup the getter and setter methods for your objects. You should define it at least in the interface, and if you decide to create a property from it then you must also synthesize it the .m file.

Since when is it possible to declare Objective-C 2.0 properties in a category?

I always thought that one cannot declare an object property in a category.
Until my partner did it in our app's code, and it seemed to work.
I went on a SO and Google binge to try to explain to him that no, Objective-C categories can only be used to add methods, not properties. I found questions such as:
Setting New Property In Category Interface Implementation (look at the accepted answer)
Can I add a property for a method not in my category?
But then I found this link on Apple's site that contains the following about the #property declaration:
A property declaration begins with the
keyword #property. #property can
appear anywhere in the method
declaration list found in the
#interface of a class. #property can
also appear in the declaration of a
protocol or category. (emphasis added)
I know that this doesn't work:
#interface MyClass ()
NSInteger foobar;
- (void) someCategorizedMethod;
#end
But this compiles:
#interface MyClass ()
#property NSInteger foobar;
- (void) someCategorizedMethod;
#end
My question is (a) what's the best practice here? and (b) is this something that is new to Objective-C 2.0, and instead of using a "real" iVar, it simply uses associative storage behind the scenes to make this work?
You have always been able to declare an #property in a category. What you couldn't do -- and still can't -- is declare storage for the property in the category, neither as an instance variable nor via `#synthesize.
However....
#interface MyClass () is not a category. It is a class extension and has a distinctly more specific role than a category.
Namely, a class extension can be used to extend a class's #interface, and this includes #properties that can be #synthesized (including synthesizing storage in the modern runtime).
Foo.h:
#interface Foo
#end
Foo.m:
#interface Foo()
#property int x;
#end
#implementation Foo
#synthesize x; // synthesizes methods & storage
#end
it simply uses associative storage
behind the scenes to make this work?
Nope -- it is a real instance variable. The modern runtime fixes the fragile base class problem.
#interface MyClass ()
NSInteger foobar;
- (void) someCategorizedMethod;
#end
The above doesn't work (as expected) because foobar is, effectively, a global variable.
If you change it to:
#interface MyClass () {
NSInteger foobar;
}
- (void) someCategorizedMethod;
#end
Then it'll work with the latest release of the llvm compiler (with the right flags, as #Joshua indicated in a comment).
Generally speaking, properties are nothing different from other methods. As long as the ivar used is available in the ordinary class, there is no problem at all. It's just syntactic sugar.
Things start to get more difficult if also the ivar is automatically created, as is possible in some configurations.
The main point here is that declaration of the ivar is independent from the property.
Assotiative storage is the solution.
Have a look at this post.

Do declared properties require a corresponding instance variable?

Do properties in Objective-C 2.0 require a corresponding instance variable to be declared? For example, I'm used to doing something like this:
MyObject.h
#interface MyObject : NSObject {
NSString *name;
}
#property (nonatomic, retain) NSString *name;
#end
MyObject.m
#implementation
#synthesize name;
#end
However, what if I did this instead:
MyObject.h
#interface MyObject : NSObject {
}
#property (nonatomic, retain) NSString *name;
#end
Is this still valid? And is it in any way different to my previous example?
If you are using the Modern Objective-C Runtime (that's either iOS 3.x or greater, or 64-bit Snow Leopard or greater) then you do not need to define ivars for your properties in cases like this.
When you #synthesize the property, the ivar will in effect be synthesized also for you. This gets around the "fragile-ivar" scenario. You can read more about it on Cocoa with Love
In your interface, you can formally declare an instance variable between the braces, or via #property outside the braces, or both. Either way, they become attributes of the class. The difference is that if you declare #property, then you can implement using #synthesize, which auto-codes your getter/setter for you. The auto-coder setter initializes integers and floats to zero, for example. IF you declare an instance variable, and DO NOT specify a corresponding #property, then you cannot use #synthesize and must write your own getter/setter.
You can always override the auto-coded getter/setter by specifying your own. This is commonly done with the managedObjectContext property which is lazily loaded. Thus, you declare your managedObjectContext as a property, but then also write a -(NSManagedObjectContext *)managedObjectContext method. Recall that a method, which has the same name as an instance variable/property is the "getter" method.
The #property declaration method also allows you other options, such as retain and readonly, which the instance variable declaration method does not. Basically, ivar is the old way, and #property extends it and makes it fancier/easier. You can refer to either using the self. prefix, or not, it doesn't matter as long as the name is unique to that class. Otherwise, if your superclass has the same name of a property as you, then you have to say either like self.name or super.name in order to specify which name you are talking about.
Thus, you will see fewer and fewer people declare ivars between the braces, and instead shift toward just specifying #property, and then doing #synthesize. You cannot do #synthesize in your implementation without a corresponding #property. The Synthesizer only knows what type of attribute it is from the #property specification. The synthesize statement also allows you to rename properties, so that you can refer to a property by one name (shorthand) inside your code, but outside in the .h file use the full name. However, with the really cool autocomplete that XCode now has, this is less of an advantage, but is still there.
Hope this helps clear up all the confusion and misinformation that is floating around out there.
it works both ways but if you don't declare them in the curly braces, you won't see their values in the debugger in xcode.
From the documentation:
In general the behavior of properties is identical on both modern and legacy runtimes (see “Runtime Versions and Platforms” in Objective-C Runtime Programming Guide). There is one key difference: the modern runtime supports instance variable synthesis whereas the legacy runtime does not.
For #synthesize to work in the legacy runtime, you must either provide an instance variable with the same name and compatible type of the property or specify another existing instance variable in the #synthesize statement. With the modern runtime, if you do not provide an instance variable, the compiler adds one for you.
If you are using XCode 4.4 or later it will generate instance variable synthesizing code for you.
You just have to declare properties like below; it will generate synthesizing code and instance variable declaring code for you.
#property (nonatomic, strong) NSString *name;
it will generate synthesizing code as
#synthesize name = _name;
and you can access instance variable using _name
it is similar to declare
NSString* _name
but if you declare read-only property it like
#property (nonatomic, strong, readonly) NSString *name;
it will generate code
#synthesize name;
or
#synthesize name = name;
So you should access instant variable name with out prefix "_"
any way you can write your own synthesizing code then compiler will generate code for you.
you can write
#synthesize name = _name;
The Objective-C Programming Language: Property Implementation Directives
There are differences in the behavior of accessor synthesis that depend on the runtime (see also “Runtime Difference”):
For the legacy runtimes, instance variables must already be declared in the #interface block of the current class. If an instance variable of the same name as the property exists, and if its type is compatible with the property’s type, it is used—otherwise, you get a compiler error.
For the modern runtimes (see “Runtime Versions and Platforms” in Objective-C Runtime Programming Guide), instance variables are synthesized as needed. If an instance variable of the same name already exists, it is used.