I have a class with the following property exposed in the .h file:
#property (readonly, nonnull) NSArray<String *> * routeContext;
As you can see this is a NSArray which is not mutable. In the implementation though I want to be able to work with this array as a mutable one (NSMutableArray) so it will be easy to add, remove objects from it.
What is the best approach to do it?
I was thinking about holder a NSMutableArray in the m file which backs the read only NSArray but it seems kinda dirty to me, is there any other suggestions?
The reason I don't want to set the property to NSMutableArray although its readonly is that readonly doesn't really make sense with NSMutableArray.
Thanks.
I would add a read-write NSMutableArray property to a class extension in the .m file. Then implement the read-only property as a method that returns a copy of the mutable property.
In the .m file:
#interface SomeClass()
#property (nonatomic, strong) NSMutableArray<NSString *> *myRouteContext;
#end
#implementation SomeClass
- (NSArray<NSString *> *)routeContext {
return [myRouteContext copy];
}
#end
In all of your implementation code you use myRouteContext. Only clients of the class use routeContext for the read-only version.
I wouldn't call this "dirty" in any way. There's still only one backing instance variable implicitly created by the myRouteContext property. No instance variables are created for the read-only routeContext property. The #property for that one is just syntactic sugar for the routeContext method you implement.
In addition to the approach suggested by HangarRash i would consider two other options:
Extending routeContext property itself in the class extension:
#interface TDWObject ()
#property (copy, nonatomic, nonnull) NSMutableArray<NSString *> *routeContext;
#end
Just introducing ivar in the class extension for the property manually (and accessing it directly in the implementation):
#interface TDWObject () {
NSMutableArray<NSString *> *_routeContext;
}
#end
Personally I would prefer the manual ivar due to the following reasons:
It doesn't introduce any redundant methods that clang would synthesise otherwise (you neither need extra getter, nor setter for a NSMutableArray *)
It's the most performant (accessing ivar directly).
I would also recommend to alter the property attributes as follows:
// The header file
#interface TDWObject : NSObject
#property (copy, readonly, nonatomic, nonnull) NSArray<NSString *> *routeContext;
#end
Here a couple of clarifications regarding the properties choice:
copy storage - technically for a readonly property storage attrbitue should not make much difference, because it predominantly denotes setter semantic (if we don't count that the value for this property can also be passed as a constructor argument). However, in our case the getter is custom and returns a copy of the internal object (instead of just reference to it). If you look through Cocoa/Cocoa Touch API, they often use copy attribute when they want to explicitly say that you deal with copies of internal data structure and any changes made to the instance obtained from the property wouldn't be tracked by the owning object. (e.g. -[NSCharacterSet invertedSet]), thus it's an important part of the interface description. Why the copy is needed at all? because otherwise the client code can easily exploit the mutability of the original data, and manage its content itself.
nonatomic atomicity - first, I don't know if there is a reason to make the property atomic, and you commonly use nonatomic properties by default (because they don't have burden of synchronisation, which slows down access/read performance). Second - clang would not be able to pair a synthesized setter with a user defined getter (if you choose to use properties approaches instead of ivar). Last, but not least - since getter is user-defined, you will have to manage the synchronisation yourself, so it doesn't come "for free".
Finally, the implementation part would look like this:
#implementation TDWObject
#pragma mark Lifecycle
- (instancetype)init {
if (self = [super init]) {
_routeContext = [NSMutableArray array];
}
return self;
}
#pragma mark Actions
- (NSArray<NSString *> *)routeContext {
return [_routeContext copy];
}
- (void)addFoo {
[_routeContext addObject:#"Foo"];
}
#end
Related
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
...
I want to create a class that serves as a base (or "abstract") class to be extended by subclasses. The best way I can explain what I'm talking about is with a few examples. Here's a possible interface for my superclass:
#import <Cocoa/Cocoa.h>
#import "MyViewControllerDelegate.h"
#interface MyViewController : NSViewController
#property (nonatomic, weak) id<MyViewModeControllerDelegate> delegate;
#property (nonatomic, copy) NSArray *content;
#end
Writing it like that seems nice and clean, but I can't access the ivars from my subclasses.
After doing some research, I've concluded that a good way to provide subclasses with direct access to ivars is to use the #protected directive and include any declarations in the header file so subclasses can see it:
#import <Cocoa/Cocoa.h>
#import "MyViewControllerDelegate.h"
#interface MyViewController : NSViewController {
#protected
__weak id<MyViewControllerDelegate> _delegate;
NSMutableArray *_content;
}
#property (nonatomic, weak) id<BSDViewModeControllerDelegate> delegate;
#property (nonatomic, copy) NSArray *content;
#end
I personally don't have an issue with that, and it seems to work the way I want it to (e.g. subclasses can access the ivars directly, but other classes have to use accessors). However, I read blog posts or Stack Overflow answers every day that say instance variables should just be synthesized, or "I don't even touch instance variables anymore."
The thing is, I started learning Objective-C post-ARC, so I'm not fully aware of the ways in which developers had to do things in the past. I personally like the control I have when I implement my own getters/setters, and I like being able to actually see instance variable declarations, but maybe I'm old school. I mean, if one should "just let the compiler synthesize the instance variables," how does one include any sort of logic or "side effects" without implementing a bunch of KVO?
For example, if my instance variables and getters/setters are synthesized, how do I initialize stuff lazily? For example, I sometimes like to do this:
- (NSArray *)myLazyArray
{
if ( _myLazyArray == nil ) {
self.myLazyArray = #[];
}
return _myLazyArray.copy;
}
Or how do I make sure that a value being set isn't the same as the currently set value? I'll sometimes implement a check in my mutator method like this:
- (void)setMyLazyArray:(NSArray *)array
{
if ( [array isEqualToArray:_myLazyArray] )
return;
_myLazyArray = array.mutableCopy;
}
I've read all of Apple's documentation, but half their docs date back to 2008 (or worse in some cases), so I'm not exactly sure they're the best place to get information on the matter.
I guess the gist of my question is this: Is there a preferred "modern" way of handling instance variables, variable synthesis, inheritance, scope, etc. in Objective-C? Bonus points for answers that don't include "Bro, Swift." or "You aren't using Swift?"
Any guidance would be much appreciated. Thanks for reading!
Why do your subclasses need access to your ivars? Ivars are an implementation detail and subclasses shouldn't be concerned with that. There could be all sorts of side effects if the parent class is doing logic in the property setter/getters. Therefore, always access them through the property.
Assuming this is in your subclass and you are overriding a property getter:
- (NSArray *)myLazyArray
{
if ( super.myLazyArray == nil ) {
// do what you need to do to populate the array
// assign it to yourself (or super)
self.myLazyArray = #[];
}
return super.myLazyArray;
}
And then for the setter:
- (void)setMyLazyArray:(NSArray *)array
{
if ( [array isEqualToArray:super.myLazyArray] )
return;
super.myLazyArray = array.mutableCopy;
}
I'm working on building an iOS 6 app.
I have a class TDBeam which inherits from superclass TDWeapon.
The superclass TDWeapon declares a #property in the TDWeapon.h file:
#interface TDWeapon : UIView
#property (nonatomic) int damage;
#end
I do not explicitly #synthesize the property, as I'm letting Xcode automatically do so.
In the subclass TDBeam I override the getter in the TDBeam.m file:
#import "TDBeam.h"
#implementation TDBeam
- (int)damage {
return _damage;
}
#end
Xcode auto-completes the getter method name, as expected. But when I attempt to reference the _damage instance variable (inherited from the superclass), I get a compiler error:
Use of undeclared identifier '_damage'
What am I doing wrong here? I've tried explicitly adding #synthesize, and changing the name of the _damage ivar, but the compiler doesn't "see" it or any other ivars from the superclass. I thought ivars were visible and accessible from subclasses?
Synthesized ivars are not visible to subclasses, whether they are explicitly or automatically created: What is the visibility of #synthesized instance variables? Since they are effectively declared in the implementation file, their declaration isn't included in the "translation unit" that includes the subclass.
If you really want to access that ivar directly, you'll have to explicitly declare it (in its default "protected" form) somewhere that the subclass can see it, such as a class extension of the superclass in a private header.
There are a lot of posts on this topic on Stack Overflow, none of which offer simple concrete advice, but this topic sums it up most succinctly, and Josh's answer is the best in any.
What he kinda stops short of saying outright, is, if this is the kind of thing you want to do, don't use #property at all. Declare your regular protected variable in your base class as he says, and write you're own setters and getters if you need them. The ivar will be visible to any subclasses who can then write their own setters/getters.
At least that's where i've landed on the issue, although I'd a total newb to subclassing.
The idea of creating private headers to host your anonymous category and re-#sythesizing your ivars in your subclass just seems wrong on so many levels. I'm also sure I've probably missed some fundamental point somewhere.
Edit
Okay after some lost sleep, and inspired by Stanford's 2013 iTunes U course, here I believe is an example solution to this problem.
MYFoo.h
#import <Foundation/Foundation.h>
#interface MYFoo : NSObject
// Optional, depending on your class
#property (strong, nonatomic, readonly) NSString * myProperty;
- (NSString *)makeValueForNewMyProperty; //override this in your subclass
#end
MYFoo.m
#import "MYFoo.h"
#interface MYFoo ()
#property (strong, nonatomic, readwrite) NSString * myProperty;
#end
#implementation MYFoo
// Base class getter, generic
- (NSDateComponents *)myProperty {
if (!_myProperty) {
_myProperty = [self makeValueForNewMyProperty];
}
return _myProperty;
}
// Replace this method in your subclass with your logic on how to create a new myProperty
- (NSString *)makeValueForNewMyProperty {
// If this is an abstract base class, we'd return nil and/or throw an exception
NSString * newMyProperty = [[NSString alloc]init];
// Do stuff to make the property the way you need it...
return newMyProperty;
}
#end
Then you just replace makeValueForNewMyProperty in your subclass with whatever custom logic you need. Your property is 'protected' in the base class but you have control over how it is created, which is basically what you are trying to achieve in most cases.
If your makeValueForNewMyProperty method requires access to other ivars of the base class, they will, at the very least, have to be be public readonly properties (or just naked ivars).
Not exactly 'over-ridding a getter' but it achieves the same sort of thing, with a little thought. My apologies if, in trying to make the example generic, some elegance and clarity has been lost.
I'd like to do the following, in an abstract way:
// .h
#interface SomeObject : NSObject
#property (readonly) NSArray myProperty;
#end
// .m
#interface SomeObject ()
#property (readwrite) NSMutableArray myProperty;
#end
#implementation SomeObject
#end
According to the section Subclassing with Properties in the Mac Developer Library it is allowed to overwrite readonly properties with readwrite. What doesn't work is using a subclass for the property type. I used NSMutableArray as an example, but it could be any other class/subclass combination.
According to inheritance rules, it should be ok though. readonly just generates the getter which also is allowed to return a subclass object.
How do you tackle such cases when you need a subclass type for some property for internal use?
An ugly way would be the following, but I'd like to avoid that as it means that I cannot use the self. getters and setters when accessing subclass methods.
// .h
#interface SomeObject : NSObject
#property (readonly) NSArray myProperty;
#end
// .m
#implementation SomeObject {
NSMutableArray _myProperty;
}
#synthesize myProperty = _myProperty;
#end
EDIT (based on your edits): Your specific case after the edit is a somewhat special and common case (if it can be both at the same time), and requires some careful consideration.
The reason this is a special is because the subclass is a mutable form of the exposed class. The caller may expect that it will not change after receiving it. But if you hand back your internal object, then it might mutate. You have several options:
Return an immutable copy. This is often the best solution for small collections. It's certainly the simplest. But if the accessor may be called often and the collection is large, it can be prohibitively expensive.
Make your internal property immutable. If requests for the property are much more common than changes to the property, it can be more efficient to recreate the object when it mutates (using arrayByAddingObject:, subarrayWithRange: and the like).
Warn the caller that the object being returned may change.... uggh... I've done this in one case where I needed the performance, but it's quite dangerous.
I've never actually done it this way, but you could also create your own copy-on-write this way: Return the mutable version directly and mark a flag that it is now "dirty." When mutation is required internally, make a mutable copy and store it in your property (letting go of the old collection). This seems a lot of complexity, but might be useful for some situations, particularly if reads and writes tend to clump separately (lots of reads followed by lots of writes).
OLD ANSWER based on NSObject vs. NSString:
I assume your goal here is to make myProperty be of some opaque type, rather than leaking the fact that it is an NSString? Perhaps so you can change your mind later on how it's actually implemented? There are a few options. The easiest is to define it of type id. Then internally just treat it as a string. id can be anything. It is usually preferred over NSObject*.
If you want more type-safety internally, then you can create a private property with another name of type NSString and return it for myProperty like this:
SomeObject.h
#interface SomeObject : NSObject
#property (readonly) id myProperty;
#end
SomeObject.m
#interface SomeObject ()
#property (readwrite) NSString *myInternalProperty;
#end
#implementation SomeObject
- (id)myProperty {
return myInternalProperty;
}
#end
Another hiding technique you can use (if hiding is very important to you) is a subclass. For example:
SomeObject.h
#class MyOpaque;
#interface SomeObject : NSObject
#property (readonly) MyOpaque *myProperty;
#end
SomeObject.m
#interface MyOpaque : NSString
#end
#implementation MyOpaque
#end
#implementation SomeObject
#end
Since the caller does not have an #interface definition for MyOpaque, he can't send messages to it without a compiler warning.
How do you tackle such cases when you need a subclass type for some
property for internal use?
Properties are explicitly not for internal use, they are members of a public interface.
If you need an internal value define a member field and override the setter of the property to set your internal value.
I was wondering what the point of #property and #synthesise were. At the moment I use the following to declare something:
//Class.m
#import "Class.h"
CCNode *node;
#implementation
//init, etc..
But I have seen others use:
#property (nonatomic, etc..) CCNode* node;
#synthesise (nonatomic, etc..) node;
//I am not too sure on how this type of declaration works, please correct me on how it's done.
They both seem to work in the same way, what are the advantages of the #property and #synthesise way? Do they do different things, if so, what?
#property and #synthesize are two objective C keyword that allow you to easily create your properties and therefore avoid to write by hand getters and setters methods of the property.
The #property define the property itself, should be placed in the header file and can get some attributes (as for example : strong, nonatomic, retain assign, copy), the #synthesize should be placed into the implementation file and tell the compiler to generate the body of getter and setter method.
These two keyword are extremely useful when coupled with the right use of their attributes, because they take care of the generation of the property code and most of all they take care of the memory management of the property.
#property - create the declaration of your getter and setter.
#synthesize - provide the definition of getter and setter based upon the parameters which are passed inside property.
Check this out, there are a lot more details about the same present there - https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html
on using #property the compiler will take care of declaring getter and setter methods based on readonly and readwrite
readonly -> getterMethod
readwrite -> both setter and getter method
on using #synthesize the compiler will take care of defining getter and setter methods
If you have an instance variable (ivar) in your class, you can't access it from other classes usually. So you have to make public accessor methods (getters and setters). They look something like this:
Setter:
- (void)setMyVariable:(SomeClass *)newValue {
if (newValue != myVariable) {
[myVariable release];
myVariable = [newValue retain];
}
}
Getter:
- (SomeClass *)myVariable {
return myVariable;
}
This was the way you had to do it before Objective-C 2.0. Now you can use #property and #synthesize to speed this up. It's basically just a shortcut.
In the header you use #property to define what kind of setters you want. Should the setter retain the passed value (like in my example) or copy or just assign?
And in the implementation you just write #synthesize to make the compiler include the automatically created getters and setters at that position. Usually at the top of your implementation.
My feeling is that all iVars should have an associated underscore synthesised property (using an _iVar prevents accidental direct access), and all access to the iVars, apart from init and dealloc methods, should via the property.
IMHO the big win is memory management - it's safer and much easier as there is no need to remember which iVars have been retained.
And think of how much work is required to code an accessor - 4 lines for getter and 2 for a setter.
At some point in the future #synthesize is likely to be optional, so all you'll need is the #property.