This question already has answers here:
property not working with getter AND setter
(4 answers)
Closed 8 years ago.
So I wanted to write a simple class.
header file
#import <Foundation/Foundation.h>
#interface Player : NSObject
#property (readonly, copy) NSString *PlayerName;
#end
class file
#import "Player.h"
#implementation Player
- (NSString*) PlayerName
{
return _PlayerName;
}
- (void)setPlayerName:(NSString *)PlayerName
{
_PlayerName = PlayerName;
}
#end
But now Xcode gives me an error, saying that the _PlayerName variable does not exist. But I thought that's the way you need to write properties access functions.
As soon as you override both the setter and getter the compiler no longer creates them for you. Since the compiler is not doing anything with the property it will no longer create the the private ivar.
So unless you need to override the setter or/and getter you better of letting the compiler create them for you.
But if you need just add #synthesize PlayerName = _PlayerName; just after the #implementation.
If you declare the setter AND the getter, you NEED to synthesize the variable, since compiler won't do it automatically for you in this case.
#synthesize PlayerName = _PlayerName;
Also you specified your property as a readonly which is not the best practice to use when you want to save something to that variable, because with dot notation you will get complier error.
Related
This question already has answers here:
Where to put iVars in "modern" Objective-C?
(5 answers)
Closed 6 years ago.
I'm a beginner to Objective-C, coming over from Swift. It seems as if there are two different #interface instances in which I can declare my ivars. One in my header file, such as this:
// Header file
#interface ViewController : UIViewController
{
// declare instance variables
}
#end
And another that I can add in my implementation file, such as this:
// Implementation file
#interface ViewController ()
// declare instance variables
#end
#implementation ViewController
#end
EDIT: I was learning the "old way" of doing things, which taught me to declare private ivars in the .h file. My confusion stemmed from seeing ivars declared in .h (old way) as well as in .m (new, preferred way). Here's what I've learned (so far...):
// .h
#interface SomeClass : UIViewController
#property (nonatomic, assign) BOOL someBool;
// declare other properties, which will all be public
#end
// .m
#interface SomeClass () <UITextFieldDelegate>
// what do I declare here?...
#end
#implementation SomeClass {
// ...and what do I declare here?
}
// method implementations
#end
However, I'm still confused as to the difference between my .m's #interface and the #implementation curly brackets. #matt said to never use curly brackets, but #rmaddy's answer here suggests that #implementation SomeClass {} is ok. So, which is it?
Do you want it to be accessible publicly? Then write in .h file.
If you don't want other classes to see it ie you want to make it private and only visible to that class itself then write in .m file.
For more information you can see this question:
Where to put iVars in "modern" Objective-C?
I have come to find that many of the times in which I want to have a synthesized readonly property, I merely implement the getter method of that property in terms of other variables with no need for an ivar, for example (Note: I am defining ivars in the interface because I am using OmniGraffle UML software and it does not recognize ivars auto-generated by synthesized properties):
#interface Editor : UIView {
BOOL _wordWrap;
BOOL _showLineNumbers;
NSDictionary *_options;
}
#property (nonatomic) BOOL wordWrap;
#property (nonatomic) BOOL showLineNumbers;
#property (nonatomic, copy, readonly) NSDictionary *options;
#end
#implementation Editor
#synthesize wordWrap = _wordWrap;
#synthesize showLineNumbers = _showLineNumbers;
#synthesize options = _options;
- (NSDictionary *)options {
return #{
#"WordWrap" : [NSNumber numberWithBool:self.wordWrap],
#"ShowLineNumbers" : [NSNumber numberWithBool:self.showLineNumbers],
};
}
#end
In the above Editor class, is it necessary for me to define the _options ivar in the header definition and more importantly does the auto-generated ivar take up memory or space in the symbol table? Also, would it be more efficient to use copy, retain, or no value in this case? Just curious.
First: stop putting your ivar declarations in your #interface. They belong in your #implementation. See this answer for a detailed explanation.
Anyway, given what you've written, your #synthesize options = _options has no effect.
That #synthesize has two possible effects:
It adds an instance variable named _options, if your class doesn't have one.
It generates a getter method, options, that returns the value of _options, if your class doesn't have a method named options.
Since you manually defined the instance variable and the getter, the #synthesize does nothing. You can remove it entirely without changing the meaning of your program.
Specifying copy on a readonly property has no effect. The copy and retain (or, more properly under ARC, strong) attributes only affect the generated setter method, and the compiler doesn't generate a setter for a readonly property. (If you change the property to readwrite in a class extension, then copy matters.)
Yes, the _options ivar takes up both memory (for each instance of Editor) and space in the symbol table.
Since you're not using the _options ivar, you should delete it entirely. You should also delete the #synthesize entirely, so the compiler doesn't generate the _options ivar for you.
This question already has answers here:
Autosynthesized property 'delegate' will use synthesized instance variable '_delegate', not existing instance variable 'delegate'
(2 answers)
Closed 9 years ago.
I'm new to protocol delegates and I am trying to understand the difference between the 2 notations below.
In my protocol delegate file, I have defined
#interface SampleProtocol : NSObject
{
id <SampleProtocolDelegate> delegate;
}
which gives me a warning, so I changed this piece of code to
#interface SampleProtocol : NSObject
{
id <SampleProtocolDelegate> _delegate;
}
and it works as I had intended it to. So I would like to know why the syntax is id _delegate whereas most tutorials I have seen is just id delegate in the protocol definition?
You have a property named delegate also, but have not included an explicit #synthesize. Implicit synthesize creates a backing instance variable with the name _propertyName. If you create an instance property with the name propertyName, the compiler is kind enough to warn you that there will be two instance variables.
If you have a property, you don't have to create the instance variable yourself. The compiler will create one for you. Leaves your code cleaner.
You always want to name ivars with a leading underscore. If you create properties, the compiler will automatically create the underscore ivar for you. To illustrate:
This code:
// header
#interface MyGreatClass : NSObject
#property NSInteger someNumber;
#end
// implementation
#implementation MyGreatClass
#end
Is the same as this:
// header
#interface MyGreatClass : NSObject {
NSInteger _someNumber;
}
- (void)setSomeNumber:(NSInteger)someNumber;
- (NSInteger)someNumber;
#end
// implementation
#implementation MyGreatClass
- (void)setSomeNumber:(NSInteger)someNumber
{
_someNumber = someNumber;
}
- (NSInteger)someNumber
{
return _someNumber
}
#end
No need for the #synthesize keyword.
One more thing: Unless you are creating a class that represents something like a network protocol, be aware that a protocol is similar to an interface in Java: https://developer.apple.com/library/ios/documentation/cocoa/conceptual/ProgrammingWithObjectiveC/WorkingwithProtocols/WorkingwithProtocols.html
This question already has answers here:
Declaration/definition of variables locations in ObjectiveC?
(4 answers)
Closed 9 years ago.
What is the proper way to work with instance variables (declared on interface), their #property and #synthesize, when working in ARC project? What I now do is following:
SomeClass.h:
#interface SomeClass : NSObject {
NSString *someString;
}
#property(nonatomic, copy) NSString* someString;
and SomeClass.m:
#implementation SomeClass
#synthesize someString;
- (void)someMethod {
self.someString = #"Foobar";
}
The thing is that there are other approaches that works, like using just the #property:
SomeClass.h:
#interface SomeClass : NSObject
#property(nonatomic, copy) NSString* someString;
Accessing the someString without self:
SomeClass.m:
#implementation SomeClass
#synthesize someString;
- (void)someMethod {
someString = #"Foobar";
}
etc. I'm new to Objective-c, I'm used to Java. What is the proper way to work with attributes then? I understand that special cases will have special behavior, but what is the best approach in general? (by general I mean I want to access the variable from the class itself and from "outside" and I want ARC to still work correctly, eg. I don't have to worry about memory leaks)
For simple properties, you don't need the instance variable declaration or the #synthesize. The clang compiler will generate both for you by default. So you could write this in the header:
#interface SomeClass : NSObject
#property (nonatomic, copy) NSString *someString;
#end
And the implementation:
#implementation SomeClass
- (void)someMethod {
self.someString = #"Foobar";
}
#end
Avoid direct instance variable access unless you are in the -init method or overriding the setter. Everywhere else you should use the dot syntax (self.someString). If you do need access to the instance variable, the default synthesize will create an underscore-prefixed ivar, e.g. _someString.
Note that for classes with mutable versions like NSString/NSMutableString and NSArray/NSMutableArray the standard practice is to use a copy property. If you use strong on a string or array, the caller might pass in a mutable version and then mutate it from under you, causing hard-to-find bugs.
Check out this SO post for information about ARC.
(Edited) The "strong" attribute tells ARC to keep an object around until the object with the property is deallocated. You do need the "copy" attribute because an NSString property could have been passed in as an NSMutableString. The "copy" guarantees that the original object will be kept around. Again, I apologize for the incorrect/misleading information I originally had here.
The reason you can access the instance variable someString as well as the property self.someString is that the #synthesize someString line creates an instance variable for the property and creates methods for getting and setting the value of it. However, it is recommended that you use the property instead of directly using the instance variable because by using the instance variable, you cannot let the parent object know that you've changed one of its properties.
I have a project which others have written and I have taken over it, hoping to make the app better.
I encountered one problem:
From one class:
I write _customclass.variable. CustomClass is another class and variable is a property and is of int type. And I get value of the variable in this class, but when I change it to self.customclass.variable, I always get 0. Is there other alternative ways to get value from other class?
(a)
#property (readwrite)int boxSpacing;
(b)
#synthesize boxSpacing;
(c)
- (id)initWithCoder:(NSCoder *)aDecoder {
self.boxSpacing = 10;
}
You asked:
Is there other alternative ways to get value from other class?
The short answer is that using the "getter" is the customary way to get a value from another class. But looking at your problem (admitted, not having enough source code to properly diagnose your issue), I'm guessing that the issue rests in the use of instance variables. But more on that later.
First, let's look at the proper use of declared properties and their instance variables and their accessor methods (the getters and setters). Generally you should set properties using these accessor methods. You can, though, use access a variable from within a class using either the instance variable (and you should not use accessor methods in initializer and dealloc methods). And when using the getter and setter, you can choose whether to use the method invocation (e.g. "[self customObject]") or the dot notation (e.g. "self.customObject").
Let's look at an example. Let's assume you have some simple CustomClass:
#interface CustomClass : NSObject
{
// you don't need to declare the instance variable
//int _boxSpacing;
}
#property (nonatomic) int boxSpacing;
#end
#implementation CustomClass
// In Xcode 4.4 and later, the synthesize statement is optional, and if you
// omit it, it will synthesize the instance variable like this, with the
// leading underscore. While you don't need to use an underscore in your
// instance variable, it has become convention in iOS development and it's
// a good technique to minimize chances that you accidentally use the instance
// variable when you actual intended to use the property's accessor methods
// (the getter and setter).
#synthesize boxSpacing = _boxSpacing;
#end
Now, let's assume that you're going to use this CustomClass from within, for example, your view controller. So, first you declare and instance of this CustomClass:
#interface MyViewController : UIViewController
{
// you do not need this instance variable declaration
// the #synthesize statement will take care of this for you
// CustomClass *_customObject;
}
#property (nonatomic, strong) CustomClass *customObject;
#end
And then let's demonstrate how to use the value property of the CustomClass object customObject from within your view controller:
#implementation MyViewController
// Again, in Xcode 4.4 and later, the synthesize statement is optional, and if you
// omit it, it will synthesize the instance variable like this, with the
// leading underscore
#synthesize customObject = _customObject;
- (void)customClassTest
{
// initialize the object
self.customObject = [[CustomClass alloc] init];
// set the property
self.customObject.boxSpacing = 1;
// finally, let's demonstrate three ways to retrieve the value
NSLog(#"%d", self.customObject.boxSpacing);
NSLog(#"%d", [[self customObject] boxSpacing]);
NSLog(#"%d", _customObject.boxSpacing);
// while we're at it, let's demonstrate other ways to set the property
_customObject.boxSpacing = 2;
// or
[[self customObject] setBoxSpacing:3];
}
Ok, so let's get back to your problem. You say:
I write _customclass.variable. CustomClass is another class and variable is a property and is of int type. And I get value of the variable in this class, but when I change it to self.customclass.variable, I always get 0.
Ok, this can be caused by a couple of different problems, but the most common problem I see is confusion between explicitly declared instance variables and the instance variables created behind the scenes by the #synthesize statement. This is why I always advise that people not explicitly define the instance variables for their declared properties, but rather let the #synthesize statement do that automatically. That way I can't have the sort of problem I'm about to demonstrate.
Consider this innocuous (though incorrect) example:
#interface MyViewController : UIViewController
{
CustomClass *_customObject;
}
#property (nonatomic, strong) CustomClass *customObject;
#end
#implementation MyViewController
#synthesize customObject;
- (void)customClassTestError
{
// initialize the object
self.customObject = [[CustomClass alloc] init];
// this works
self.customObject.boxSpacing = 1;
// this doesn't!
_customObject.boxSpacing = 2;
// when it hits this statement, the value will still be 1!!!
NSLog(#"%d", self.customObject.boxSpacing);
}
Do you see the problem? While I declared an instance variable with the underscore, _customObject, when the compiler hit the #synthesize statement, it created another instance variable, this time without the leading underscore, customObject. Thus, my explicitly declared instance variable never received the init/alloc and therefore is nil and thus any attempts to use it won't work!
Typically we see the converse problem (an explicitly declared instance variable without the underscore and a #synthesize statement of the form #synthesize customObject = _customObject), but hopefully you'll get the idea.
Anyway, this is the most common example of what would cause the behavior you describe. If this isn't what's going on, please provide us a more extensive code sample.
But if you're having problems, I'd always suggest that you check the value of your CustomClass object, itself, before you try to access its properties. Make sure the class object itself has been properly initialized (whether for the reasons I list above, or some other initialization problem) before you try to use its properties. You can do something like NSLog(#"CustomClass object = %#", customObject); or NSAssert(customObject, #"Object not properly initialized");.
Have you defined a #property for the CustomClass? If so, have you assigned a value?
If not, then you're sending the message variable to nil. And in your case that will result to 0.