I have this structure:
#interface MyList : NSObject {
NSString* operation;
NSString* link;
}
#property (readwrite) NSString* operation;
#property (readwrite, assign) NSString* link;
#end
#implementation MyList
#synthesize operation,link;
#end
I know that if I had retain instead of readwrite I should release the operation and link properties.
BUT should I release the operation and link with the code above?
No. You did not New, Alloc, Retain, or Copy the values in there, so you do not (Auto)release them.
The default values are readwrite, assign, and atomic. So by not specifying assign, retain, or copy in your first example you are essentially using assign by default. This is why you wouldn't subsequently use a release. Assign does not increase the retain count of an object. Note that for objects such as your string you almost would never want to use assign because you don't own the object and it could get released on you. So for objects you want to use either retain or copy. You would only use assign on scalar types like floats, NSIntegers, BOOLs etc. Note also that if you are not using garbage collection you get a compiler warning if you don't specify assign, retain, or copy.
Related
In Objective-C, it's common to declare NSString/NSArray/NSDictionary as copy, is it necessary to do that for a readonly property or there is no difference? If an NSString is readonly, it will never be set, so declaring it strong or copy will have the same effect right?
//use strong rather copy here and it will work the same since it will
never be copied?
#property (nonatomic, readonly) NSString *string;
If it really is read-only then you don't need to specify it. If you're going to redeclare it privately to be readwrite then you do want to specify it. For readonly properties it has no effect as no setter will be created.
You're right, but there're some things to consider. That's okay as long, as your property is immutable object. However, it is not always true.
First example, which I run into frequently, is when you have actually mutable object inside of your implementation. Like property declared NSArray in implementation can actually be NSMutableArray. Strong reference property getter for it will return pointer to that NSMutableArray. And, at some point, you'll run into situation when you request NSArray from object, work with it some time and than - boom!!! - your NSArray have different elements of number of it? What the hell? In that case, it's better idea to copy your inner implementation used NSMutableArray in getter.
Another example is some model object
#interface Person : NSObject <NSCopying>
#property NSString *name;
#property NSDate *birthdate;
#end
And you have some other interface with property
#property (strong, readonly) Person *person;
Yeah, you will not assign different object to this property. However, you'll be able to modify its fields, so it will represent some completely different Person. If you don't want such behaviour - make it copy property. Or make it private with access methods to get its fields
- (id) getHiddenPersonPropertyValueForKey:(NSString *)personPropertyKey;
Or any other way
If property represents really immutable value (NSArray, NSIndexSet, etc), then just readonly is fine, as it will be returned immutable as-is.
But in case of your private ivar being mutable (NSMutableArray ivar vs property's NSArray type), you should return a copy to prevent leaks of future internal changes into caller's state.
#interface MyObject : NSObject {
NSMutableArray *_array;
}
#property(nonatomic, readonly) NSArray *array;
// -or-
- (NSArray *)array;
#end
and
#implementation
#dynamic array; // only if #property was declared in interface
- (NSArray *)array
{
return [_array copy];
}
#end
The caller is safe then to store property's value and expect that it will not change even without making explicit copy itself:
self.array = [myObject array]; // e.g. 1 element
[myObject addElementToArray:#(42)];
NSLog(#"%#", self.array); // still 1 element
#interface ChargeView (){
NSString* billid;
int clickRow;
NSMutableArray *arr1;
}
#property (nonatomic, strong) NSMutableArray *arr2;
What's the difference between arr1 and arr2? Which is better or write it anywhere if I like?
The property also generates the accessors -(NSMutableArray *)arr2 (getter) and -(void)setArr2:(NSMutableArray *)arr2 (setter). It further generates a corresponding instance variable _arr2 (the underscore is convention for ivars). The attributes of the property determine the behavior of the accessors. For instance, if the property is marked atomic, the accessors will synchronize access to the ivar.
On the other hand, arr1 is just an ivar and you have to write accessors (if you need any) yourself.
If I declare an instance variable
#implementation Person {
NSString *name; // would this be atomic, strong, readwrite?
}
Does it get the same default attributes as if I declared it a property (atomic, strong, readwrite)
#interface Person()
#property NSString *name; // would be atomic, strong, readwrite by default
#end
ivars and local variables are strong by default (under ARC). Variables are read-write unless the appropriate use of const is applied. And variable access is non-atomic unless specific steps are taken to make the access atomic.
So essentially, ivars and local variables behave as strong, non-atomic, read-write.
Nope. Instance variables don't get attributes like atomic, strong, etc., at all -- those are only attributes that apply to properties. (If you're using ARC, they'll be treated as a strong variable, though.)
I'm trying to get the property attributes of an object with the property_getAttributes() runtime function. Some properties are set read-only. But the problem comes when I try to make the difference between retain/strong, weak and assign properties. e.g.:
Let's say we have:
#interface MyObject : NSObject
#property (assign, readonly) NSObject *prop1;
#property (strong, readonly) NSObject *prop2;
#property (weak, readonly) NSObject *prop3;
#end
We get the property list and print
int outCount;
objc_property_t *properties = class_copyPropertyList([MyObject class], &outCount);
for(i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
const char *c_attributes = property_getAttributes(property);
printf("%s", c_attributes);
}
free(properties);
The result is:
T#"NSObject",R,V_prop1
T#"NSObject",R,V_prop2
T#"NSObject",R,V_prop3
...so no specific code for weak, strong/retain, assign properties when they are read-only :(
The question is: is there any other way to know if the property is weak, strong/retain, assign?
I haven't tried your code, but according to
https://developer.apple.com/library/mac/documentation/cocoa/conceptual/objcruntimeguide/articles/ocrtpropertyintrospection.html
R The property is read-only (readonly)
C The property is a copy of the value last assigned (copy).
& The property is a reference to the value last assigned (retain).
N The property is non-atomic (nonatomic).
G The property defines a custom getter selector name. The name follows the G (for example, GcustomGetter,).
S The property defines a custom setter selector name. The name follows the S (for example, ScustomSetter:,).
D The property is dynamic (#dynamic).
W The property is a weak reference (__weak).
P The property is eligible for garbage collection.
t Specifies the type using old-style encoding.
To answer your question quickly, the answer is no.
The issue here is that memory management semantics for properties (those are assign, unsafe_unretained, strong, weak, copy in ARC and assign, retain, copy in MRC) only have any application in automatically generated setter code. Should you write your own setter for the property you are of course encouraged to implement the semantic yourself (but not required). The getter of these properties are not modified at all by these property attributes. Consider this code:
#interface FooBar ()
#property (nonatomic, strong, readonly) NSString* foobar;
#end
#implementation FooBar
- (NSString*) foobar {
return [NSString stringWithFormat:#"aString"];
}
In these situations the caller will make a either a strong or weak reference and the return value must live for at least as long as the calling code needs to complete the statement. In the case of a weak reference it will go to nil afterwards since a property with strong does not guarantee that the referenced object will be kept for you. Ultimately, memory management on readonly properties are nothing more than a placebo that end up there mostly by either habit or style #property (nonatomic, readonly) ... is perfectly legal, but confusing when we are used to encountering a memory attribute in the property declaration.
PS: There's another function in the runtime called property_copyAttributeList which I find much easier for parsing this information (it uses structs to break up the components for you).
This is my code:
#interface Object : NSObject {
#private
NSArray *array;
}
#property NSArray *array;
#end
And the #synthesize in the implementation. I get a compiler warning in the line with the #property:
warning: default assign attribute on property 'array' which implements NSCopying protocol is not appropriate with -fobjc-gc[-only]
If I write the property as #property (assign) NSArray *array it does not show up. What is this about?
In your case you are creating a property that is a pointer to an object. Assign, which is the default, is not appropriate for objects, which should be declared as retain or copy.
In your case you should define your property as:
#property (nonatomic, copy) NSArray *array;
You could use retain instead of copy here, but there are good reasons to use copy.
edit
To answer the deeper question you seem to be asking - have a look at this thread from the Cocoa mailing lists.
Are you using the LLVM compiler or gcc?
Properties default to assign. Your property is an assign.
Regarding assign vs copy in GC enabled app, I found this via google...
http://www.cocoabuilder.com/archive/cocoa/194064-use-of-assign-vs-copy-for-accessors-in-garbage-collected-app.html
I think we usually use assign, but will use copy if needed, like for example, for NSString object. So to get rid of warning, we just explicitly specify it as assign.