I know someone already asked about Writing getter and setter for BOOL variable. But, if I'm defining a custom getter & setter methods setImmediate & isImmediate, respectively, I'd like passcode.immediate = NO to work too.
I do not have any instance variables, but maybe I should? I could add one for NSDate *lastUnlocked.
Here's the relevant code so far:
// PasscodeLock.h
extern NSString *const kPasscodeLastUnlocked;
#interface PasscodeLock : NSObject {
}
- (BOOL)isImmediate;
- (void)setImmediate:(BOOL)on;
- (NSDate *)lastUnlocked;
- (void)resetLastUnlocked;
- (void)setLastUnlocked:(NSDate *)lastUnlocked;
#end
// PasscodeLock.m
#import "PasscodeLock.h"
NSString *const kPasscodeLastUnlocked = #"kPasscodeLastUnlocked";
#implementation PasscodeLock
#pragma mark PasscodeLock
- (BOOL)isImmediate {
return self.lastUnlocked == nil;
}
- (void)setImmediate:(BOOL)on {
if (on) {
[self resetLastUnlocked];
} else {
self.lastUnlocked = nil;
}
}
- (NSDate *)lastUnlocked {
return [[NSUserDefaults standardUserDefaults] objectForKey:kPasscodeLastUnlocked];
}
- (void)resetLastUnlocked {
NSDate *now = [[NSDate alloc] init];
self.lastUnlocked = now;
[now release];
}
- (void)setLastUnlocked:(NSDate *)lastUnlocked {
[[NSUserDefaults standardUserDefaults] setObject:lastUnlocked forKey:kPasscodeLastUnlocked];
}
Then, in a view controller that has PasswordLock *passwordLock as an instance variable, I want to do passcode.immediate = NO, but I get the error "Property 'immediate' not found on object of type 'PasscodeLock *'."
How do I get passcode.immediate = NO to work?
You need something like
#property (nonatomic, getter=isImmediate) BOOL immediate;
in your .h file and of course a #synthesize statement in your .m file. This creates the property AND defines your getter method name.
Declare such property in the #interface:
#interface PasscodeLock : NSObject {
}
#property(dynamic, getter=isImmediate,
setter=setImmediate:) BOOL immediate;
// etc.
#end
(The setter= part is optional)
I think the issue ids that your getter and setter names are not consistent. By default, if you have
foo.immediate
in your code, it is assumed that the getter and setter are named -immediate and -setImmediate: respectively. Your getter is not named correctly. The best way around this is to declare a property as Mark and Kenny have already said but you could also change the name of your getter.
The point is that you do not need declared properties to use dot syntax, but if you are going to use dot syntax then declared properties are the recommended way of declaring the getter and setter.
Related
I've got an NSManagedObject class that I want to override a setter to but I've been told it's good practice to not modify the automatically generated class file and create categories to instead extend them (because if you change the model and regenerate the file, you lose all your additions).
If I make a method for the setter in a category, it definitely runs the method (tested with NSLog), but I don't know how to assign the actual property value. Normally, I'd synthesise the property using
#synthesize finished = _finished;
so that I can access the property in the setter using _finished, like so:
- (void)setFinished:(NSNumber *)finishedValue {
_finished = finishedValue;
self.end_time = [NSDate date];
}
but where the property is defined in the NSManagedObject this doesn't seem possible.
You can do with subclassing see the doc here
- (void)setName:(NSString *)newName
{
[self willChangeValueForKey:#"name"];
[self setPrimitiveName:newName];
[self didChangeValueForKey:#"name"];
}
In a category, you can't add property value, only methods. So you will need to subClass in order to perform what you want.
There is an easy way to do so, try the following:
Model.h
#interface Model
#property(nonatomic,copy) NSString * string;
#end
Model + Override.m
#interface Model ()
{
NSString *_string;
}
#end
#implementation Model (Override)
- (void)setString:(NSString *)string
{
return _string = string;
}
#end
If I create a #property and synthesize it, and create a getter and setter as well like so:
#import <UIKit/UIKit.h>
{
NSString * property;
}
#property NSString * property;
--------------------------------
#implementation
#synthesize property = _property
-(void)setProperty(NSString *) property
{
_property = property;
}
-(NSString *)property
{
return _property = #"something";
}
Am I correct in assuming that this call
-(NSString *)returnValue
{
return self.property; // I know that this automatically calls the built in getter function that comes with synthesizing a property, but am I correct in assuming that I have overridden the getter with my getter? Or must I explicitly call my self-defined getter?
}
is the same as this call?
-(NSString *)returnValue
{
return property; // does this call the getter function or the instance variable?
}
is the same as this call?
-(NSString *)returnValue
{
return _property; // is this the same as the first example above?
}
There are a number of problems with your code, not least of which is that you've inadvertently defined two different instance variables: property and _property.
Objective-C property syntax is merely shorthand for plain old methods and instance variables. You should start by implementing your example without properties: just use regular instance variables and methods:
#interface MyClass {
NSString* _myProperty;
}
- (NSString*)myProperty;
- (void)setMyProperty:(NSString*)value;
- (NSString*)someOtherMethod;
#end
#implementation MyClass
- (NSString*)myProperty {
return [_myProperty stringByAppendingString:#" Tricky."];
}
- (void)setMyProperty:(NSString*)value {
_myProperty = value; // Assuming ARC is enabled.
}
- (NSString*)someOtherMethod {
return [self myProperty];
}
#end
To convert this code to use properties, you merely replace the myProperty method declarations with a property declaration.
#interface MyClass {
NSString* _myProperty;
}
#property (nonatomic, retain) NSString* myProperty
- (NSString*)someOtherMethod;
#end
...
The implementation remains the same, and works the same.
You have the option of synthesizing your property in your implementation, and this allows you to remove the _myProperty instance variable declaration, and the generic property setter:
#interface MyClass
#property (nonatomic, retain) NSString* myProperty;
- (NSString*)someOtherMethod;
#end
#implementation MyClass
#synthesize myProperty = _myProperty; // setter and ivar are created automatically
- (NSString*)myProperty {
return [_myProperty stringByAppendingString:#" Tricky."];
}
- (NSString*)someOtherMethod {
return [self myProperty];
}
Each of these examples are identical in how they operate, the property syntax merely shorthand that allows you to write less actual code.
return self.property – will call your overridden getter.
return _property; – accesses the property's instance variable directly, no call to the getter.
return property; – instance variable.
EDIT: I should emphasize that you will have two different NSString variables -- property and _property. I'm assuming you're testing the boundaries here and not providing actual production code.
above answer elaborate almost all the thing , i want to elaborate it little more.
// older way
#interface MyClass {
NSString* _myProperty; // instance variable
}
- (NSString*)myProperty; // getter method
- (void)setMyProperty:(NSString*)value;//setter method
#end
the instance variable can not be seen outside this class , for that we have to make getter and setter for it.
and latter on synthesis it in .m file
but now
we only used
#property(nonatomic) NSString *myProperty;
the #property is an Objective-C directive which declares the property
-> The "`nonatomic`" in the parenthesis specifies that the property is non-atomic in nature.
-> and then we define the type and name of our property.
-> prototyping of getter and setter method
now go to .m file
previously we have synthesis this property by using #synthesis , now it also not required it automatically done by IDE.
little addition : this `#synthesis` now generate the getter and setter(if not readonly) methods.
This works fine:
NSString *myVariable;
- (IBAction) doFirstAction {
myVariable = #"123456789";
}
- (IBAction) doSecondAction {
NSLog(#"%#",myVariable);
}
However, if I do this (substituting the #"123456789" for some code which returns the same value ie "123456789") I cannot access the value in doSecondAction.
NSString *myVariable;
- (IBAction) doFirstAction {
myVariable = [imageNode getAttributeName:#"value"];
}
- (IBAction) doSecondAction {
NSLog(#"%#",myVariable);
}
Any clue as to why I cant access myVariable outside of doFirstAction?
you need to retain it
myVariable = [[imageNode getAttributeName:#"value] retain];
see also
Another way of doing this would be to define an accessor method that does the retaining for you. Thus in your interface definition:
#property (retain) NSString *myVariable;
and later in your implementation:
#synthesize myVariable;
Now Xcode generates getter and setter methods for you that will handle the retain statement for you. However, you now need to use the dot notation, since the equals sign is not overridden, and your setter method is not called unless you do so:
self.myVariable = [imageNode getAttributeName:#"value"];
What it says on the tin: I'd like to use the #property/#synthesize syntax to define a property on my Objective-C 2.0 class, but I want to place restrictions on the range of values allowed in the property. For example:
#interface MyClass : NSObject {
int myValue;
}
#property (nonatomic) int myValue;
Implementation:
#implementation MyClass
#synthesize myValue(test='value >= 0');
Note that the syntax here is just an example. Is this, or something much like it possible? Alternately, what is the literal equivalent of a synthesized setter, so that I can ensure that I use the same object retention rules in my manual setters as is used in a synthesized one.
Assuming your properties are Key-Value compliant (as they would be if you are using #synthesize) you should also implement Key-Value compliant validators. Take a look at Apple's documentation on the matter: http://developer.apple.com/documentation/Cocoa/Conceptual/KeyValueCoding/Concepts/Validation.html
The important thing to note is that validation does not happen automatically except when using certain kinds of binding. You either call the validator directly or by calling validateValue:forKey:error:.
You could override the produced setter to call the validator before saving it but if you are using bindings this is probably not what you want to do as the validator will possibly be called more than once for a single modification.
Also note that the validator might change the value being validated.
So lets look at your example (untested, btw. I'm not near a Mac):
#implementation MyClass
#synthesize myValue;
-(BOOL)validateMyValue:(id *)ioValue error:(NSError **)outError
{
if (*ioValue == nil) {
// trap this in setNilValueForKey
// alternative might be to create new NSNumber with value 0 here
return YES;
}
if ( [*ioValue intValue] < 0 ) {
NSString *errorString = #"myValue must be greater than zero";
NSDictionary *userInfoDict = [NSDictionary dictionaryWithObject:errorString
forKey:NSLocalizedDescriptionKey];
NSError *error = [[[NSError alloc] initWithDomain:#"MyValueError"
code:0
userInfo:userInfoDict] autorelease];
*outError = error;
return NO;
} else {
return YES;
}
}
If you wanted to override the synthesised setter and make it do the validation (still untested):
- (void)setMyValue:(int)value {
id newValue = [NSNumber numberWithInt:value];
NSError *errorInfo = nil;
if ( [self validateMyValue:&newValue error:&errorInfo] ) {
myValue = [newValue intValue];
}
}
You can see we had to wrap the integer in an NSNumber instance to do this.
When you use the #synthesize the accessor methods are generated. You can implement your own which will overwrite the generated one.
You can put your own implementation inside the accessor methods, e.g. you can add value checking before assignment and so on.
You can ommit one or the other or both, the ones that you don't implement will be generated because of #synthesize, if you use #dynamic you are specifying that you will provide accessors either at compile or run time.
Accessors will have names derived from the property name myproperty and setMyproperty. The method signatures are standard so it is easy to implement your own. The actual implementation depends on property definition (copy, retain, assign) and if it is read-only or not (read-only doesn't get set accessor). For more details see objective-c reference.
Apple reference:
#synthesize You use the #synthesize
keyword to tell the compiler that it
should synthesize the setter and/or
getter methods for the property if you
do not supply them within the
#implementation block.
#interface MyClass : NSObject
{
NSString *value;
}
#property(copy, readwrite) NSString *value;
#end
#implementation MyClass
#synthesize value;
- (NSString *)value {
return value;
}
- (void)setValue:(NSString *)newValue {
if (newValue != value) {
value = [newValue copy];
}
}
#end
i want to pass a variable from a viewcontroller to another the way i do is
at the first viewcontroller header file i declared a variable
1.h:
NSString *string;
and at the second viewcontroller i have import the 1.h in my 2.m file,the way i call the variable is
2.m:
NSString *string2 = 1.string
however it return an error can somebody teach me how to do,because of i dont have the strong basic at Object Oriented programming ,thanks
Just defining and declaring the two strings is not enough. That makes sure that each class has a variable called string or string2 - but when your program is running, it is actual objects that must refer to specific instances of string1 (or string2).
It's like designing a house with a letterbox - the letterbox is there on the plan of the house, but nothing happens until a specific letter gets sent to a specific house.
What you need to do is wire up the actual instances of your class, possibily in an init method, like this:
// 1.h
#interface ViewController1 : UIViewController
{
// declare our variable
NSString* string1;
}
// declare 'string1' as a property
#property (retain) NSString* string1;
// 1.m
// implements the property for string1
#synthesize string1;
// 2.h
#interface ViewController2 : UIViewController
{
// declare our variable
NSString* string2;
}
// declare 'string2' as a property
#property (retain) NSString* string2;
// 2.m
- (id)initWithTitle:(NSString*)aTitle andString1:aString
{
if (self = [super init])
{
self.title = aTitle;
self.string1 = aString;
}
return self;
}
Then in 1.m, you create the second controller, and wire the strings up, like this:
// 1.m
mySecondController = [[ViewController2 alloc] initWithTitle:#"Controller 2" andString:string1];
Although it is possible to directly access members variables like that (using the -> operator) it is not recommended.
The correct way is to provide an accessor to get/set your member variables.
In Objective-C 2.0 (iPhone and OSX 10.5) you can easily do this using the "property" keyword. As part of the property syntax you can also express how you wish "set" objects to be treated.
retained - the previous object will be released and the new one retained
copy - the object will be copied
assign - the object will be assigned.
These are the basics, I suggest you read up more about properties.
The below shows how you would use properties in your example. Note that because we are dealing with an NSString, which is an NSObject derived class, we use the "retain" option to ensure the reference counts are correctly updated.
// 1.h
#interface ViewController1 : UIViewController
{
// declare our variable
NSString* _string;
}
// declare 'string' as a property
#property (retain) NSString* string;
// 1.m
// implements the property for string
#synthesize string = _string;
// constructor for ViewController1
-(id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle {
if (self = [super initWithNibName: name bundle: bundle]) {
// Initialize the string here.
self.string = #"Hello World";
}
}
// 2.m
NSString* oldString = view.string;
view.string = #"New String";