Hiding privately mutable properties behind immutable interfaces in Objective-C - objective-c

So, what I basically want to ask is whether the following code is safe (not whether it works, because it does). I.e, will the public getter override the synthesized getter of the actionLog property [which is of a different type]?
.h file:
#interface SomeClass : NSObject
- (NSArray*) actionLog;
#end
.m file:
#interface SomeClass ()
#property (strong, nonatomic) NSMutableArray* actionLog;
#end
#implementation SomeClass
...
#end

This is not only OK, it is exactly why class extensions were created in the first place!
Yes, there will be a single automatically synthesized ivar and pair of getter/setter methods generated as expected.
Sorry -- missed the NSArray vs. NSMutableArray part. No, you can't do that; the types must be the same.
However, you don't want to return your mutable array anyway. First, the caller might modify it (a bug). But, more importantly, the caller will assume that the contents are immutable as implied by the API) and, thus, when that array's contents change out from under the caller, it may cause issue (example; caller can reasonably assume that the result of count will be stable and can be cached).

By backing the property with a mutable ivar, like this:
.h file:
#interface SomeClass : NSObject
#property (nonatomic, strong) NSArray *actionLog;
#end
.m file:
#implementation SomeClass{
NSMutableArray* _actionLog;
}
-(void)insertAction:(Action *)action{
if(!_actionLog){
_actionLog = [[NSMutableArray alloc] init];
}
[_actionLog addObject:action];
}
#end

Related

Hiding implementation details with .h and .m in objc

I'm confused about something. If in your .h file you have:
#property (nonatomic, strong, readonly) NSArray *categories;
and then in the .m you have:
#interface MyClass ()
#property (nonatomic, strong, readwrite) NSMutableArray *categories;
#end
If I want to later set categories in the .m file, I can do:
[self setCategories:[NSArray arrayWithArray:categories]];
But then Xcode complains that incompatible pointer types sending NSArray to NSMutableArray. I'm basically trying to hide the implementation details and have the .m use a NSMutableArray and to a consumer
use an NSArray.
[self setCategories:[NSMutableArray arrayWithArray:categories]]; // this gives no Xcode warning
By using the [NSMutableAray arrayWithArray:] method, does it still prevent the consumer of my Class from mutating my categories array?
You've done all you can in objc.
Your internal readwrite declaration needs a mutable array, so Xcode's complaining is right, you have to use a mutable for the setter.
The consumer can do everything with that object, even if it's declared as NSArray you can find out it's a NSMutableArray in reality and change it.
You can't prevent that. But your public declaration shows it should be assumed immutable. There's nothing more you can do.

What to use for Objective-C objects instead of structs when using ARC?

ARC forbids Objective-C objects in structs or unions.
Unless you add __unsafe_unretained which means its not managed.
I was wonder what people are using in place of structs now if anything?
Or are you retaining everything manually?
It's very simple - if you want to add an object inside a struct, you are doing it wrong. Whenever you need a struct to hold an obj-c object, convert the struct into an obj-c object.
I would manage different objects in one objc-object like this:
#class MyFirst, MySecond;
#interface MyContainer : NSObject
#property (nonatomic, strong, readonly) MyFirst *firstInst;
#property (nonatomic, strong, readonly) MySecond *secondInst;
// optional: convenience initializer
+ (instancetype)containerWithFirstInst:(MyFirst *)firstInst secondInst:(MySecond *)secondInst;
#end
// required by linker: stub definition for the class declared above
#implementation MyContainer
#end
#interface SomeController : NSObject
- (void)doSomething;
#end
#implementation SomeController
- (void)doSomething {
MyFirst *firstInstance = [[MyFirst alloc] initWithSomeParameters:...];
MySecond *secondInstance = [[MySecond alloc] initWithSomeParameters:...];
MyContainer *container = [MyContainer containerWithFirstInst:firstInstance secondInst:secondInstance];
// use container as a struct (but it's definitely an object that is managed by ARC)
}
#end
Wouldn't it be a lot easier to implement a static class and fake its properties, as shown here?
I answered to it here https://stackoverflow.com/a/28845377/1570826
maybe somebody with the right level could mark this or the other as a duplicate.

Confusing Objective-C class structure

Here's a (reduced) class declaration from an example on apple's developer:
#interface myController : UITableViewController {
NSArray *samples;
}
#property (nonatomic, retain) NSArray *samples
What is the purpose of declaring
{
NSArray *samples;
}
when you declare it again as a property? If you leave out:
{
NSArray *samples;
}
you can still use #synthesize in your .m and get a reference to it!
I'm a little confused as to the purpose of the first declaration.
Thanks
Properties are just a handy way to declare accessors to you data. It usually leads to some member variable but not necessarily. And that member var can have different name:
#interface myController : UITableViewController {
NSArray *mSamples;
}
#property (nonatomic, retain) NSArray *samples
#end
#implementation
#synthesize samples = mSamples;
#end
Or you can use properties without vars at all:
#interface myController : UITableViewController {
}
#property (nonatomic, retain) NSArray *samples
#end
#implementation
-(NSArray*) samples {
//you can for example read some array from file and return it
}
-(void) setSamples:(NSArray*) arr {
//write that array to file or whatever you want
}
#end
With new compiler you can use properties without ivars at all, compiler will generate them for you implicitly.
With a property declaration, there is no purpose or benefit in explicitly declaring the backing instance variable. It's just leftovers from habit.
Edit: For iOS or Mac 64-bit Intel, explicitly declaring ivars was never needed for properties. But they were needed for other Mac work — hence the examples.
Also, I did find a difference. When an ivar is explicitly declared, unless you state otherwise, it is a protected ivar, available to subclasses. But when an ivar is implicitly created for a property, subclasses don't have access to the ivar.

#property and #synthesize

I'm very new to Objective C. (Two days now). When read about #synthesize, it seemed to overlap with my understanding #property (which I thought I understood) ... So, some details need to be ironed out in my mind ... it's bugging me.
Please correct me if I'm wrong about differences of #property and #synthesize:
If you declare a #property in your #interface, then you're telling the world that users can expect to use standard getters and setters for that property. Futhermore, XCode will make generic getters and setters for you. ... BUT, To what degree does that happen with the #property declaration? ( I.E. does that mean "completely" ... like unseen declarations for it in your #interface, and also unseen code in your #interface?
-Or-
Does #property take care of the unseen code declarations in your #interface only - whereas #synthesize takes care of the unseen code implementation in your #implementation section? )
First, note that the latest version of Xcode does not require #synthesize at all anymore. You can (and should) just omit it. That said, here's what the pieces do.
#property is a declaration of accessors. It is just a declaration. There is very little difference between the following:
#property (nonatomic, readwrite, strong) NSString *something;
vs.
- (NSString *)something;
- (void)setSomething:(NSString)aSomething;
The main difference is that declaring these methods using #property lets the compiler automatically generate (synthesize) the implementations for you. There is no requirement that you let the compiler do it for you. You are absolutely free to implement something and setSomething: by hand, and it is common to do. But, if you don't implement them by hand, the compiler will automatically create an ivar for you called _something and create a reasonable implementation for the getter and setter.
In older versions of Xcode, you had to explicitly request the auto-generation using the #synthesize keyword. But that is no longer required. Today, the only reason to use #synthesize is if you want the ivar to have a non-standard name (never do that).
A key point here is that the methods something and setSomething: are just methods. There is nothing magical about them. They're not special "property methods." They're just methods that by convention access a piece of state. That piece of state is often stored in an ivar, but does not need to be.
To be even more clear: object.something does not mean "return the ivar named _something from object." It means "return the result of [object something], whatever that does." It is common for that to return the value of an ivar.
You should declare all of your state (internal and external) using #property declarations, and you should avoid directly declaring ivars. You should also always access your properties via their accessors (self.something), except in the init and dealloc methods. In init and dealloc, you should directly use the ivar (_something).
#property declares a property on your class with whatever atomicity and setter semantics you provide.
With Xcode 4.4, autosynthesis is available wherein you are provided with a backing ivar from your property without declaring it in #synthesize. This ivar has the form of _propertyName where your property name is propertyName.
Objective-C #property and #synthesize
#property
generates get/set method
today(from Xcode v4.4 with the LLVM v4.0) #property additionally uses #synthesize inside
#synthesize propertyName = _propertyName
#synthesize:
generates a new iVar or link with existing iVar
generates an implementation of the get/set method with an appropriate iVar
[Case when #synthesize can be used]
#property
#interface SomeClass : NSObject
#property NSString *foo;
#end
//generated code
#interface SomeClass : NSObject
- (NSString *)foo;
- (void)setFoo:(NSString)newFoo;
#end
#synthesize pattern
#synthesize <property_name> = <variable_name>;
//Using
//1. Specify a variable. New variable(variableName) will be generated/linked with existing
#synthesize propertyName = variableName
//if variableName is not exist it generates:
//NSString *variableName;
//read access
NSString *temp = variableName;
//2. Default. New variable(propertyName - the same name as a property) will be generated/linked with existing
#synthesize propertyName
//is the same as
//#synthesize propertyName = propertyName
//if propertyName is not exist it generates:
//NSString *propertyName;
//read access
NSString *temp = propertyName;
//if you specify not-existing <property_name> you get
//Property implementation must have its declaration in interface '<class_name>' or one of its extensions
previously you had to use next syntax:
#interface SomeClass : NSObject
{
//1. declare variable
NSString *_foo;
}
//2. create property
#property NSString *foo;
#end
#implementation SomeClass
//3. link property and iVar
#synthesize foo = _foo;
#end
But today you can use next syntax
#interface SomeClass : NSObject
//1. create property
#property NSString *foo;
#end
Next, the same code, will be generated for both cases
#interface SomeClass : NSObject
{
//variable
NSString *_foo;
}
//getter/setter
- (void)setFoo:(NSString *)newFoo;
- (NSString *)foo;
#end
#implementation SomeClass
- (void)setFoo:(NSString *)newFoo
{
_foo = newFoo;
}
- (NSString *)foo
{
return _foo;
}
#end

Subclass Properties

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.