inherit an immutable copy property as mutable retain - objective-c

I am having the following code:
#interface Room : NSObject
{
#protected
NSMutableDictionary* mCustomProperties;
}
#property (readonly, copy) NSDictionary* CustomProperties;
#end
#interface MutableRoom : Room
{
}
#property (readwrite, retain) NSMutableDictionary* CustomProperties;
#end
These properties are then implemented later by accessing mCustomProperties.
I know, that it is not allowed to redeclare the memory management attribute or the data type of a property in a subclass to differ from the ones in the base class.
However, I want to achieve the following:
- Give only readonly access to the dictionary in the immutable base class. As the member is a NSMutableDictionary, just returning it as a retained instance of NSDictionary would mean, that it simple cast would make it mutable again, even unintended, when the user of the property stores the access variable somewhere as an NSObject instance and then recovers the original type of it back later. Therefor I want to return the mutable dictionary by immutable copy in the readonly property.
- Give full readwrite access to the dictionary in the mutable sub class. As you should not only be able to store another dictionary there, but also to just change the content of the existing one, I would like the property in the subclass not only to be readwrite, but also to be retained, instead of copied, so that the original values will be accessed, and to access it as an NSMutableDictionary, not as a NSDictionary, so that one can add, remove or change entries of the dictionary through the property.
Is there any more elegant way than suppressing the warning or using two differently named properties?

when declaring a mutable/immutable pair of a class cluster, i often find it simplest to not inherit from another, but to use an inner class for the implementation, like so:
// Room.h
#interface Room : NSObject
// ...
#end
#interface MutableRoom : Room
// ...
#end
// MONRoom.h
#class RoomImp;
#interface MONRoom : Room
{
#private
RoomImp * imp;
}
#property (readonly, copy) NSDictionary* CustomProperties;
#end
#interface MONMutableRoom : MutableRoom
{
#private
RoomImp * imp;
}
#property (readwrite, retain) NSMutableDictionary* CustomProperties;
#end
// RoomImp.h
#interface RoomImp : NSObject
{
#private
NSMutableDictionary* mCustomProperties;
}
// ...
#end

Related

Hiding privately mutable properties behind immutable interfaces in 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

Objective C: Should I assign the variable AND create a property or is just one of them enough?

I have got a header file (.h) and I want to declare name but all these ways work the same I think because I haven't seen any difference with functionality. Could you tell me what the difference is between:
This with both declarations:
#interface someClass : UIViewController
{
NSString *name;
}
#property (nonatomic, copy) NSString *name;
#end
Without variable:
#interface someClass : UIViewController
{
}
#property (nonatomic, copy) NSString *name;
#end
Or Without property:
#interface someClass : UIViewController
{
NSString *name;
}
#end
#interface someClass : UIViewController
{
NSString *name;
}
#property (nonatomic, copy) NSString *name;
#end
Doing this you will explicitly declare both a property and an ivar.
A property is just a set of methods:
- (void)setName:(NSString*)name;
- (NSString*)name;
An ivar is the memory store holding the value that the property methods manage. This allows you to do:
self.name = ... // access through setter method
name = ... // direct access
The advantage of using properties is that they deal with memory management for you. E.g., in your case, the property is of type copy: this means that with the first syntax (self.name = ...) a copy of the object will be done. If not using properties, you would explicitly need to do: name = [originalString copy]; to obtain the same effect.
Other options you can specify for properties (but not ivars) are: strong and weak ownerships.
Furthermore, a property also represents a public interface to access the variable from outside your class.
Using direct access you are on your own as to memory management (if you are not using ARC).
If you are using ARC and don't define properties, you will not be able to control how the memory is managed by specifying the ownership: strong, weak, retain).
#interface someClass : UIViewController
{
}
#property (nonatomic, copy) NSString *name;
#end
Here you only declare the properties; the ivar is "inferred" by the #synthesize directive in your implementation file. This is only possible in Objective C 2.0 and later (previously, the ivar declaration as above was mandatory).
The same considerations as above applies, with a minor nuance: with older versions of LLVM (ObjC compiler) you will not be able to reference directly the auto-synthesized ivar; with current version of LLVM, if you omit the #synthesize directive, then an automatic ivar named after your property would also be declared (in your case it would be _name).
This last paragraph may seem a bit "advanced", or contrived, but you can safely ignore it.
#interface someClass : UIViewController
{
NSString *name;
}
#end
In this case you are only declaring the ivar. No accessor methods. You will need to handle memory management on your own (if not using ARC), futhermore you will not be able to access the variable from outside the class. For that you need accessors.
Hope this helps.
Case 1:
The is the old method, here the #property and variable are not related until you #synthesize name = name;
Access methods :
variable : name = #"hello"; //direct access to viariable
setter/getter : self.name = #"hello" // set value to name using setName: selector
With the latest xcode just the property is enough.
Case 2:
the new xcode style. Here the synthesize and variable creation is taken care by the compiler. (so less 2 lines of code and this also helps with memory management)
Access methods :
variable : _name = #"hello"; //direct access to viariable
setter/getter : self.name = #"hello" // set value to name using setName: selector
Case 3:
Here the name is just a variable and it dose not have a setter or a getter.
with out property (or) setter & getter this is as good as a local variable and it cannot be accessed from other objects.

Can transformable attributes in Core Data entities be pointers to c structs? My transformer is not being called

I'm trying to make a CoreData-persisted entity. This entity has a few properties, one of which is a non-standard attribute, state. The state attribute is a pointer to a C struct with a few properties in it. Here's what my data model looks like:
Entities:
MDInstance
Attributes:
duration: Integer 16
moves: Integer 16
name: String
state: Transformable. I set the Transformer to MDStateTransformer.
I generated my class and edited the state property. This is what the interface looks like:
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import "MDState.h" // this is where the State structure is defined
#interface MDInstance : NSManagedObject
#property (nonatomic, retain) NSNumber * duration;
#property (nonatomic, retain) NSNumber * moves;
#property (nonatomic, retain) NSString * name;
#property (nonatomic) State *state; // note that this is a pointer to a struct
#end
This is what the implementation looks like:
#import "MDInstance.h"
#implementation MDGameInstance
#dynamic duration;
#dynamic moves;
#dynamic name;
#synthesize state;
#end
I created a value transformer called MDStateTransformer. The implementation of this is (probably) not important. Suffice it to say I have allowsReverseTransformation returning YES, transformedValueClass returning [NSValue class], and I've implemented transformedValue: and reverseTransformedValue:
Lastly, I registered the MDStateTransformer in my AppDelegate's application:didFinishLaunchingWithOptions: like this:
MDStateTransformer *transformer = [[MDStateTransformer alloc] init];
[NSValueTransformer setValueTransformer:transformer forName:#"MDStateTransformer"];
If I create a new instance of my MDInstance, set it's attribute -including the state attribute- and then try to save the entity, my transformer is never called.
I put a stop point in my transformer's init method and it is being instantiated. I put another in transformedValue: and it the function is not being called.
However, if I update my MDInstance so that the state attribute is not a pointer, but is simply a State structure, and I update the transformer to work with a struct and not a pointer, the transformedValue: is called.
Is it possible to have a custom attribute on an object which is a pointer to a c struct? If so, any ideas what I'm doing wrong?
Your transformable attribute also needs to be specified as #dynamic and not #synthesize in your implementation file. By synthesizing that property you provide an getter and setter outside of core data and thus the Core Data provided accessors will not be used.

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.

private property in Objective C

Is there a way to declare a private property in Objective C? The goal is to benefit from synthesized getters and setters implementing a certain memory management scheme, yet not exposed to public.
An attempt to declare a property within a category leads to an error:
#interface MyClass : NSObject {
NSArray *_someArray;
}
...
#end
#interface MyClass (private)
#property (nonatomic, retain) NSArray *someArray;
#end
#implementation MyClass (private)
#synthesize someArray = _someArray;
// ^^^ error here: #synthesize not allowed in a category's implementation
#end
#implementation MyClass
...
#end
I implement my private properties like this.
MyClass.m
#interface MyClass ()
#property (nonatomic, retain) NSArray *someArray;
#end
#implementation MyClass
#synthesize someArray;
...
That's all you need.
A. If you want a completely private variable. Don't give it a property.
B. If you want a readonly variable that is accessible external from the encapsulation of the class, use a combination of the global variable and the property:
//Header
#interface Class{
NSObject *_aProperty
}
#property (nonatomic, readonly) NSObject *aProperty;
// In the implementation
#synthesize aProperty = _aProperty; //Naming convention prefix _ supported 2012 by Apple.
Using the readonly modifier we can now access the property anywhere externally.
Class *c = [[Class alloc]init];
NSObject *obj = c.aProperty; //Readonly
But internally we cannot set aProperty inside the Class:
// In the implementation
self.aProperty = [[NSObject alloc]init]; //Gives Compiler warning. Cannot write to property because of readonly modifier.
//Solution:
_aProperty = [[NSObject alloc]init]; //Bypass property and access the global variable directly
It depends what you mean by "private".
If you just mean "not publicly documented", you can easily enough use a class extension in a private header or in the .m file.
If you mean "others are not able to call it at all", you're out of luck. Anyone can call the method if they know its name, even if it is not publicly documented.
As others have indicated, (currently) there is no way to truly declare a private property in Objetive-C.
One of the things you can do to try and "protect" the properties somehow is to have a base class with the property declared as readonly and in your subclasses you can redeclare the same property as readwrite.
Apple's documentation on redeclared properties can be found here: http://developer.apple.com/library/ios/DOCUMENTATION/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW19