Problem
I want to create an interface with this signature, but without auto-synthesized instance variables:
#interface MyObject : NSObject
#property (nonatomic, copy) NSArray *values;
#end
Question:
Is it possible to prevent instance variable to be auto synthesized in .m #implementaion, as I want to implement my own getter and setter and I'm not going to use instance variable.
Reason:
The reason is that I don't want to have memory overhead, as data is going to be stored in plain bytes archive. At the same time I don't want users to know implementation issues and keep interface signature unchanged.
#implementation MyObject {
NSData *_data
{
- (NSArray *)values
{
// Generate NSArray from _data
}
- (void)setValues(NSArray *)values
{
// Set _data from values
}
#pragma mark - Hidden init
- (id)initWithData:(NSData *)data
{
// Set _data
}
#end
If you implement both getter and setter yourself, instance variables are not synthesized.
As others said - if you override the setter and getter - the compiler does't do anything else. So what you want.. is what you have typed out.
If you dont wantbto create just create only instance variable.
#interface MyObject : NSObjet
{
NSArray *values;
}
#end
Related
I have a class below:
#interface Person : NSObject {
NSString *_firstname;
}
#property NSString *firstName;
#end
#implementation Person
#synthesize firstname;
#end
This will declare three variables: firstname, self.firstname and _firstname
What is the difference between the three variables and how do you using with each case?
In modern Objective-C you don't need to create instance variable if you already synthesizing properties.
From what you write it appears that you are confusing properties and ivar.
Properties create getters and setters to your ivars, but they are not ivars, they are methods that access you ivars to set or get their values.
Your class can be sum up like that:
#interface Person : NSObject
#property NSString *firstName;
#end
#implementation Person
#end
At compile time this will ensure that you can access your ivar using methods and name your ivar as _firstName.
Dot notation create access to properties so self.firstName (using ARC and default property option -nonatomic,strong-)calls that method
- (NSString*)firstName
{
return _firstName;
}
While calling self.firstName = #"foo"; calls:
- (void) setFirstName:(NSString*)name
{
if (_firstName == name) {
return;
}
_firstName = name;
}
Underlining implementation could be a little different.
The first one NSString *_firstname; is an instance variable. The #property is a property which is syntesized (you don't have to manually synthesize properties in modern Objective-C). When you declare a property you can access its instance variable with _propertyName or with self.propertyName.
It is up to you whether you declare your variables as instance variables or as properties but it is more common and suggested to declare them as properties (using properties you can have access to getters and setters, which means that you can run code before the value of the property will be set or will be read).
You can chain instance with property using
#interface Person : NSObject {
NSString *_firstname;
}
#property NSString *firstName;
#end
#implementation Person
#synthesize firstName = _firstname;
#end
Both pointers are pointing same instance now.
I have 3 properties id_1, id_2, id_3
id_2 and id_3 are derived from id_1
id_1 can have public getter/setter
id_2 and id_3 only have readonly access.
So I need to override the setter for id_1 to set id_2 and id_3 for valid id_1
id_1 could come from NSUserDefaults which means in init, I need to set id_2 and id_3
So, I wanted to call setter of id_1 from init as if I was calling from outside of the class using ivar _id_1
That would give me a single implementation to set all the ids both during init phase or if called externally
My question is on following two lines that I have in my code as I am calling the setter for id_1 with argument as ivar _id_1
_id_1 = id_from_ns_user_defaults
[self setid_1:_id_1];
In few other SO articles I saw concerns around recursive loops
Custom Getter & Setter iOS 5
.h file
#interface UserCredentials : NSObject
#property (strong, nonatomic) NSString *id_1;
#property (readonly) NSString *id_2;
#property (readonly) NSString *id_3;
#end
.m file
#interface UserCredentials ()
#property (readwrite) NSString *id_2;
#property (readwrite) NSString *id_3;
#end
#implementation UserCredentials
- (id)init
{
self = [super init];
if (self) {
/* Is this valid in Objective-C */
_id_1 = id_from_ns_user_defaults
[self setid_1:_id_1];
}
return self;
}
- (void)setid_1:(NSString *)id
{
if (id && ![id isEqualToString:#""]) {
_id_1 = id;
_id_2 = convert2(_id_1);
_id_3 = convert3(_id_1);
}
}
#end
Your highlighted concern is around creating an assignment cycle. Because you are assigning to the ivar itself, you will not be creating a cycle. Remember that manipulating the ivar will not cause your getter/setter to be called -- it's just a pointer like any other pointer.
Setting an ivar to itself is not an issue unless you have done something in your setter implementation to make it an issue. In non-ARC systems, you could easily create a bad access error by implementing your setter with the wrong order:
- (void)setVal:(NSObject *)val {
[_val release];
_val = [val retain];
}
This is countered by using autorelease instead (or assigning to a temporary variable and releasing after the retain).
Most of the time, though, your setter won't be doing anything destructive when passed a new (or same) value. Your implementation does not do this.
I am trying to do very simple operation.
in "TestFile.h" file i've declare property:
#property (nonatomic) NSDictionary *justTest;
and in implementation file "TestFile.m":
-(NSDictionary *)justTest:(NSString *) mystring {
NSLog(#"Here is my string: %#", mystring);
return nil;
}
Now i am trying to call "justTest" from another file. What i am doing:
#import "TestFile.h"
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSDictionary *testFile = [[TestFile alloc] init];
[testFile justTest:#"Hello World!"]
}
This works fine until i'm trying to pass parameter.
if i just execute
[testFile justTest];
it works, but when i try to pass parameter
[testFile justTest:#"Hello World!"];
does not work and the debug message is:
no visible #interface for 'TestFile' declares the selector 'justTest':
What is wrong with me?
You need to make this method public by adding method name to TestFile.h file before #end:
-(NSDictionary *)justTest:(NSString *) mystring;
Just to let you know when you add #property compiler synthesise it (create) two method getter, exactly the same name as your property and setter compiler add 'set' prefix, for example, you declare:
#property (nonatomic) NSDictionary *justTest;
compiler will create two methods:
-(NSDictionary *)justTest {...}
-(void)setJustTest {...}
You need to know that in your code you override the getter method.
Declare your method in TestFile.h file before calling from an external class.
-(NSDictionary *)justTest:(NSString *) mystring;
There are many questions concerning the category-properties problem.
I know some possibilities to address this:
use a singleton registry
objc_setAssociatedObject and objc_getAssociatedObject
From my point of view both is not clean since the memory allocated is never cleared when the object that created such properties is deallocated.
Categories are a good way to keep code clean and dynamically add functionality to already existing classes. They help to group functionality and to distributed implementation work among more developers.
The bad about categories is the missing storage.
I came across this problem several times now and I'm wondering whether the following would address this problem in an clean way that also takes care about the memory and if there are any problems that I can't see right now.
There is one restriction, that I can ignore since I'm working as a framework developer: I'm able to create my own root class that all my other classes can inherit from.
First of all declare the new root object:
#interface RootObject : NSObject
- (void)setRuntimeProperty:(id)runtimeProperty forKey:(id<NSCopying>)key;
- (id)runtimePropertyForKey:(id)key;
#end
With the corresponding implementation:
#import "RootObject.h"
#interface RootObject ()
#property (readwrite) NSMutableDictionary *runtimeProperties;
#end
#implementation RootObject
#synthesize runtimeProperties = _runtimeProperties;
- (id)init {
self = [super init];
if (self)
{
_runtimeProperties = [[NSMutableDictionary alloc] initWithCapacity:1];
}
return self;
}
- (void)dealloc {
[_runtimeProperties release];
_runtimeProperties = nil;
[super dealloc];
}
- (id)runtimePropertyForKey:(id)key {
return [self.runtimeProperties objectForKey:key];
}
- (void)setRuntimeProperty:(id)runtimeProperty forKey:(id<NSCopying>)key {
if (key)
{
if (runtimeProperty)
{
[self.runtimeProperties setObject:runtimeProperty forKey:key];
}
else
{
[self.runtimeProperties removeObjectForKey:key];
}
}
}
#end
By using this RootObject instead of NSObject it should be very easy to add a "property" to a category on a class. Consider having some class MyClass
#interface MyClass : RootObject
// some interface here
#end
When implementing a special behavior on top of this class you are now able to add a property like this:
#interface MyClass (specialBehavior)
#property (nonatomic, retain) NSString *name;
#property (nonatomic, copy) NSDate *birthday;
#end
With corresponding implementation:
#implementation MyClass (specialBehavior)
#dynamic name;
- (NSString *)name {
return [self runtimePropertyForKey:#"name"];
}
- (void)setName:(NSString *)name {
[self setRuntimeProperty:name forKey:#"name"];
}
#dynamic birthday;
- (NSDate *)birthday {
return [self runtimePropertyForKey:#"birthday"];
}
- (void)setBirthday:(NSDate *)birthday {
[self setRuntimeProperty:[birthday copy] forKey:#"birthday"];
}
#end
Such an implementation could KVO compatible as well by just adding the necessary calls in the setter method.
Very straight forward, but I'm wondering whether I missed something important? (E.g. very very bad runtime performance having many such declared properties or using many of these objects)
This is effectively the same as objc_setAssociatedObject and objc_getAssociatedObject, which do release memory when the object is deallocated (depending on the association type). I would guess they also have much lower overhead than your suggested code.
I just started programming in XCode and I need your help.
I have two voids; in the first void I create a NSString, and in the second void I need the value of that string, but i don't know how to obtain that value.
This is a shortend version of my .h file
//.h file
-(void)viewDidLoad
{
[self ActionOne];
}
-(IBAction)ButtonClick (id):sender
{
[self ActionTwo];
}
-(void)ActionOne
{
NSString *VarString = #"hello";
}
-(void)ActionTwo
{
NSLog (#"%#", VarString);
}
My problem is that NSLog's output is 'null', I hope someone can help me
You have declared a local variable in ActionOne. It only lives as long as the method is running. For persistent storage, you need an ivar (that's a term used in Objective-C to mean an "instance variable", which is a variable for which there is a separate copy for each object that is an instance of a class). The easiest way to do this is to declare a property, which will create an ivar and methods to access it for reading and writing. In your .h file:
#interface MyViewController: UIViewController
#property (nonatomic, strong) NSString *varString;
// ... method declarations, etc
#end
And then in your .m file:
-(void)actionOne
{
self.varString = #"hello";
}
-(void)actionTwo
{
NSLog(#"%#", self.varString);
}