Memory semantics of a computed array property? - objective-c

This is for an app that allows users to tag things. Tags are just strings.
An array of TagHolder objects holds a list of all tags in use in the app, with a boolean telling if the tag is selected, but this is an implementation detail.
The external interface calls for two methods, selectedTags, and setSelectedTags: which return and accept an arrays of strings.
I would like these two methods to work as accessors for a declared property selectedTags.
Now, my question is:
What would be the correct memory management semantics to declare for that property?
The code pattern that I have in mind is this (code not tested, so please bear with typos):
#interface TagInfo : NSObject
#property (strong, nonatomic) NSString *tag;
#property (nonatomic) BOOL selected;
#end
#interface SomeClass : NSObject
#property (memorytype, nonatomic) NSArray *selectedTags;
#end
#implementation TagHolder
- (NSArray *)selectedTags
{
// tagInfoArray is an array of all TagInfo objects
NSPredicate *selPred = [NSPredicate predicateWithFormat: #"selected == YES"];
NSArray *selectedTagInfoObjects = [[self tagInfoArray] filteredArrayUsingPredicate: selPred];
NSArray *selectedTags = [selectedTagInfoObjects valueForKey: #"tag"];
return selectedTags;
}
- (void)setSelectedTags: (NSArray *)selectedTags
{
for (TagInfo *tagInfo in [self tagInfoArray]) {
tagInfo.selected = [selectedTags containsObject: tagInfo.tag];
}
}
#end
What should memorytype be? Obviously not strong or weak, but I think it could be any one of assign, copy or even unsafe_unretained, but which one is the most correct for a computed property with an object value?
I normally use ARC, but I guess the question is the same in an environment with manual retain count.

memorytype is significant only when you #synthesize your property accessors. Since you are providing your own implementation for both the getter and the setter, the things you put in parentheses after #property are ignored; I usually put readonly or readwrite there, just to remind myself of what kind of access is available on these properties.
Your code is correct, it will work without creating memory issues with or without ARC.

Related

In ObjectiveC, is it necessary to declare strong vs copy for a readonly property?

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

Conflict between declaring instance variable and property

I am studying Objective-C. I asked a question about this code earlier but I came up with further questions. The below code is trying to make NSArray externally but really makes NSMutableArray internally so I can add pointers or remove in NSMutableArray
I face two questions.
1) What is the purpose of doing like this? Is there a specific reason you make NSArray externally? Why can't I just declare a property of NSMutableArray?
2)I learn that instance variable (_assets) is made when I declare a property of NSArray *assets. And I also declared NSMutableArray *_assets under the interface. I think those two _assets conflict each other even though they have different types. Am I thinking this in a wrong way?
#interface BNREmployee : BNRPerson
{
NSMutableArray *_assets;
}
#property (nonatomic) unsigned int employeeID;
#property (nonatomic) unsigned int officeAlarmCode;
#property (nonatomic) NSDate *hireDate;
#property (nonatomic, copy) NSArray *assets;
I'll try put your answers the way you have asked them. Let hope they clear your doubts. By now I guess you would be knowing that NSArray once initialised with data you wont be able to add or delete the data inside it which is different from NSMutableArray.
The benefit here no one else can change your externally visible data. Also when you try to sort or iterate the array you are sure that no other data would be removed or added. Also if you use NSMutableArray for such cases the application would crash if you add data while you iterate the array.
Like #KirkSpaziani Explained
#synthesize assets = _assets;
would create an instance variable for your property. However you are actually supposed to use this _assets only in getter and setter. Else places you should be using self.assets.
You can also synthesize your other array NSMutableArray *_assets as follows
#synthesize _assets = __assets;
Which would have double underscore, but frankly we shouldn't be using the underscore for a starting variable name. Plus would be great if you have different names altogether.
Also with advances in Objective C you dont require to synthesize these variables at all. Just use the self.variableName and you can access it.
Hope it clears some of your queries.
Put
{
NSMutableArray *_assets;
}
in the #implementation block
#implementation {
NSMutableArray *_assets;
}
Putting the NSMutableArray in the implementation block hides the fact that it is mutable from consumers (it is no longer in the header file).
Follow it with:
#synthesize assets = _assets;
This might not be necessary actually, but makes things clearer. When you declare a property an ivar will be automatically created (unless you #dynamic the property). However an explicitly declared ivar of the same name will override the automatically created one - so long as the type is the same or a subclass.
The reason to make it an NSArray publicly visible is so that no one else can mutate your data structure. You will have control of it. If it is an NSMutableArray internally then you can add and remove items without exposing that functionality to consumers.
You can declare your property to be readonly or readwrite - a readwrite NSArray means you can replace the whole array with a property set, but you can't add or remove items. If internally you are adding and removing items, this can make things messy. Try to stick with readonly when having a mutable internal version.
Here's something you can do if you want _assets to be a mutable array, but you don't want other classes to modify it, implement the setter and getter of the assets property so they look like this (implementing the getter and the setter will cause the property to not be synthesised, which means the NSArray *_assets will not be created automatically):
-(NSArray *)assets{
return [_assets copy]; // Copy creates an immutable copy
}
-(void)setAssets:(NSArray *)assets{
_assets = [NSMutableArray arrayWithArray:assets];
}
Keep in mind that if you access the assets array a LOT, it might be slow since you're creating an immutable copy every time, so you can create an NSArray whenever your _assets array is modified and return that in the -(NSArray *)assets method
The reason you'd internally keep an NSMutableArray, but expose an NSArray externally is so that users of your API won't abuse it and mutate its data. Keeping it visible as immutable makes people less prone to mess with it.
Another approach you could take to this is to not use a property at all, but simply have a getter and a mutable property in a class extension. For example, in your .h:
#interface BNREmployee : BNRPerson
- (NSArray *)assets;
#end
In your .m
#interface BNREmployee ()
// Inside of the class manipulate this property
#property (nonatomic, strong) NSMutableArray *mutableAssets;
#end
#implementation BNREmployee
// Clients of your class rely on this
- (NSArray *)assets
{
// copy makes the result immutable
return [self.mutableAssets copy];
}
#end
Another approach might be to make the property only writable to the implementation of you class.
To do that you declare your property as readonly in the header:
//BNREmployee.h
#property (nonatomic, readonly) NSMutableArray *assets;
Than declare it as readwrite inside an inner interface in your implementation:
//BNREmployee.m
#interface BNREmployee()
#property (nonatomic, readwrite) NSMutableArray *assets;
#end
#implementation
...

Custom class NSObject not key value coding compliant [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why is my object not key value coding-compliant?
I'm having a dictionary and I want to add keys/values to a custom class, but i always get the error, that the class is not KVC compliant, but the Apple documents state that it should be.
My code:
ContactObject.h:
#interface ContactObject : NSObject
+ (ContactObject *)testAdding;
#end
ContactObject.m:
#implementation ContactObject
- (id)init {
self = [super init];
if (self) {
// customize
}
return self;
}
+ (ContactObject *)testAdding
{
// create object
ContactObject *theReturnObject = [[ContactObject alloc] init];
[theReturnObject setValue:#"Berlin" forKey:#"city"];
[theReturnObject setValue:#"Germany" forKey:#"state"];
return theReturnObject;
}
#end
I think I'm missing something very stupid :)
Please, any help appreciated ...
Greetings,
matthias
Actually to be KVC compliant:
How you make a property KVC compliant depends on whether that property is an attribute, a to-one relationship, or a to-many relationship. For attributes and to-one relationships, a class must implement at least one of the following in the given order of preference (key refers to the property key):
The class has a declared property with the name key.
It implements accessor methods named key and, if the property is mutable, setKey:. (If the property is a Boolean attribute, the getter accessor method has the form isKey.)
It declares an instance variable of the form key or _key.
I don't see any of these three implemented. You need to have at least properties that you are trying to set through KVC, the default NSObject implementation is able to set properties through setValue:forKey: but you must declare them.
You need to declare every property that will be used:
#interface ContactObject : NSObject
#property (nonatomic,copy, readwrite) NSString* city;
#property (nonatomic, copy, readwrite) NSString* state;
+ (ContactObject *)testAdding;
#end
Or use a NSMutableDictionary object.
For example:
NSMutableDictionary* dict= [NSMutableDictionary new];
[dict setObject: #"Berlin" forKey: #"city"];
[dict setObject: #"Germany" forKey: #"state"];
You need to actually declare/implement properties. Key-Value Coding doesn't mean that every NSObject is automatically a key/value dictionary.
In this case you would need to declare:
#property (nonatomic, readwrite, copy) NSString* city;
#property (nonatomic, readwrite, copy) NSString* state;
in your #interface declaration.
ObjC is dynamic in some ways, but it's not really dynamic as far as storage in classes. If you want ContactObject to be KVC-compliant for certain keys, those keys need to exist in the class. The KVC Guide has this to say:
For properties that are an attribute or a to-one relationship, this
requires that your class:
Implement a method named -<key>, -is<Key>, or have an instance
variable <key> or _<key>. Although key names frequently begin with a
lowercase letter, KVC also supports key names that begin with an
uppercase letter, such as URL.
If the property is mutable, then it should also implement -set<Key>:.
Your implementation of the -set<Key>: method should not perform
validation.
The easiest way to accomplish that is to declare the keys you want as properties:
#property (copy, nonatomic) NSString * city;
#property (copy, nonatomic) NSString * state;
You can also declare an ivar and implement accessors yourself, but there's usually no good reason to do it that way -- declared properties will take good care of you.

Is dot syntax or bracket syntax correct for property access?

Suppose I have
#interface A : NSObject
#property (nonatomic, strong) NSMutableArray *array;
#end
Later on in another class B, I want to access that array, to check how many items are in it. I can do one of two things in B (a is an instance of A):
Option 1
[a.array count]
Option 2
[[a array] count];
Which option is the best way to do this? Is option 2 the right way to access the array when using [a array] as the getter method?
both are the same if you have synthesized the array. in first one you just call the property and in 2nd one you are calling the getter method which was generated by #synthesize action.
and sure the 2nd option is the right way as #synthesize makes two methods
1- getter that is same as the property name
2- setter that is add set with property name at start with first letter captial like setArray.
There is no difference between the two if you have synthesized the array, as The Saad said. However, I recommend bracket syntax as to remain consistent in all your method calling as all other Objective-C methods (aside from functions from C) use bracket syntax to be called.
There's no difference until you decide to rename the generated getter/setter methods and the message is likely to become invalid.
For the public instance variables you can skip the accessor methods (both property and method styles) and use the structure dereference operator:
#interface A : NSObject
{
NSMutableArray *array;
}
#property (nonatomic, strong) NSMutableArray *array;
#end
classA.m
[self->array count];
classB.m
[a->array count];
Doing this, you waive the convenience of both operation and memory management optimizations which you have using properties (in both access styles) with the different attributes, see more.
As example for the NSString property
#property (readwrite, copy) NSString *sVar;
the generated setter looks like this:
-(void)setSVar:(NSString*)inSVar
{
if (self->sVar != inSVar)
{
[self->sVar release];
self->sVar = [inSVar copy];
}
}

Is there a difference between an "instance variable" and a "property" in Objective-c?

Is there a difference between an "instance variable" and a "property" in Objective-c?
I'm not very sure about this. I think that an "property" is an instance variable that has accessor methods, but I might think wrong.
A property is a more abstract concept. An instance variable is literally just a storage slot, like a slot in a struct. Normally other objects are never supposed to access them directly. A property, on the other hand, is an attribute of your object that can be accessed (it sounds vague and it's supposed to). Usually a property will return or set an instance variable, but it could use data from several or none at all. For example:
#interface Person : NSObject {
NSString *name;
}
#property(copy) NSString *name;
#property(copy) NSString *firstName;
#property(copy) NSString *lastName;
#end
#implementation Person
#synthesize name;
- (NSString *)firstName {
[[name componentsSeparatedByString:#" "] objectAtIndex:0];
}
- (NSString *)lastName {
[[name componentsSeparatedByString:#" "] lastObject];
}
- (NSString *)setFirstName:(NSString *)newName {
NSArray *nameArray = [name componentsSeparatedByString:#" "];
NSArray *newNameArray [[NSArray arrayWithObjects:newName, nil] arrayByAddingObjectsFromArray:[nameArray subarrayWithRange:NSMakeRange(1, [nameArray size]-1)]];
self.name = [newNameArray componentsJoinedByString:#" "];
}
- (NSString *)setLastName:(NSString *)newName {
NSArray *nameArray = [name componentsSeparatedByString:#" "];
NSArray *newNameArray [[nameArray subarrayWithRange:NSMakeRange(0, [nameArray size]-2)] arrayByAddingObjectsFromArray:[NSArray arrayWithObjects:newName, nil]];
self.name = [newNameArray componentsJoinedByString:#" "];
}
#end
(Note: The above code is buggy in that it assumes the name already exists and has at least two components (e.g. "Bill Gates" rather than just "Gates"). I felt that fixing those assumptions would make the actual point of the code less clear, so I'm just pointing it out here so nobody innocently repeats those mistakes.)
A property is a friendly way of implementing a getter/setter for some value, with additional useful features and syntax. A property can be backed by an instance variable, but you can also define the getter/setter to do something a bit more dynamic, e.g. you might define a lowerCase property on a string which dynamically creates the result rather than returning the value of some member variable.
Here's an example:
// === In your .h ===
#interface MyObject {
NSString *propertyName;
}
// ...
#property (nonatomic, retain) NSString *propertyName;
// === In your .m #implementation ===
#synthesize propertyName /* = otherVarName */;
The #property line defines a property called propertyName of type NSString *. This can be get/set using the following syntax:
myObject.propertyName = #"Hello World!";
NSLog("Value: %#", myObject.propertyName);
When you assign to or read from myObject.propertyName you are really calling setter/getter methods on the object.
The #synthesize line tells the compiler to generate these getter/setters for you, using the member variable with the same name of the property to store the value (or otherVarName if you use the syntax in comments).
Along with #synthesize you can still override one of the getter/setters by defining your own. The naming convention for these methods is setPropertyName: for the setter and propertyName (or getPropertyName, not standard) for the getter. The other will still be generated for you.
In your #property line you can define a number of attributes in parens for the property that can automate things like thread-safety and memory management. By default a property is atomic meaning the compiler will wrap #synthesized get/set calls with appropriate locks to prevent concurrency issues. You can specify the nonatomic attribute to disable this (for example on the iPhone you want to default most properties to nonatomic).
There are 3 attribute values that control memory management for any #synthesized setters. The first is retain which will automatically send release to old values of the property, and retain to the new values. This is very useful.
The second is copy which will make a copy of any values passed in rather than retaining them. It is good practice to use copy for NSString because a caller could pass in an NSMutableString and change it out from under you. copy will make a new copy of the input which only you have access to.
The third is assign which does a straight pointer assign without calling retain/release on the old or new object.
Lastly you can also use the readonly attribute to disable the setter for the property.
I use properties for the interface part - where the object interfaces with other objects
and instance variables are stuff that you need inside your class - nobody but you is supposed to see and manipulate those.
By default, a readwrite property will be backed by an instance variable, which will again be synthesized automatically by the compiler.
An instance variable is a variable that exists and holds its value for the life of the object. The memory used for instance variables is allocated when the object is first created (through alloc), and freed when the object is deallocated.
Unless you specify otherwise, the synthesized instance variable has the same name as the property, but with an underscore prefix. For a property called firstName, for example, the synthesized instance variable will be called _firstName.
Previously people use properties publicly and ivars for private usage, but since several years ago, you can also define properties in #implementation to use them privately. But I'd still use ivars when possible, since there are less letters to type, and it runs faster according to this article. It makes sense since properties are mean to be "heavy": they are supposed to be accessed from either generated getters/setters or the ones manually written.
However, in recent codes from Apple, ivars are not used anymore. I guess because it's more like objc rather than C/C++, plus it's easier to use properties with assign, nullable, etc.
Objective-C Property vs Instance variable (iVar)
[Swift variable, property...]
Instance variable
#interface SomeClass: NSObject
NSString *someVariable;
#end
Property
#interface SomeClass: NSObject
#property (nonatomic, strong) NSString *someVariable;
#end
Property uses Instance variable inside. property = variable + bounded getter/setter. It is a method call with variable syntax and access
#property generates getter and setter methods(accessor methods) which uses backing ivar(aka backing field) which you can use via underscore _<var_name> (_someVariable).
Since it calls a method - method dispatch mechanism is used that is why KVO[About] can be applied
When you override accessor methods backing iVar is not generated that is why you can declare a new property explicitly or use #synthesize[About] to generate a new one or link with existing
#import "SomeClass.h"
#interface SomeClass()
#property (nonatomic, strong) NSString *someVariable;
#end
#implementation SomeClass
- (void) foo {
//property getter method
NSString *a1 = self.someVariable; //NSString *a1 = [self someVariable];
//property setter method
self.someVariable = #"set someVariable"; //[self setSomeVariable:#"set someVariable"];
//iVar read
NSString *a2 = _someVariable;
//iVar write
_someVariable = #"set iVar";
}
//if you overriding someVariable getter and setter the iVar(_someVariable) is not generated, that is why you can:
//1. create some variable explicitly
NSString *_someVariable;
//or
//2. use #synthesize
#synthesize someVariable = _someVariable;
//overriding
- (NSString*) someVariable {
return _someVariable;
}
- (void)setSomeVariable: (NSString*) updatedSomeVariable {
_someVariable = updatedSomeVariable;
}
#end
[property attributes]