I've been upgrading a project to use Realm as the persistence store and I'm not able to find any documentation on how to use an array of strings in one of my models.
The implementation of an Array for a RLMObject is to use an RLMArray where T inherits RLMObject
I could make an object that inherits.. property inside which is string... but that seems like quite some overhead to replace an NSArray of strings.
Does anyone know the recommended best practice to do this?
As of Realm Cocoa 3.0 you can simply do RLMArray<RLMString> *array; and no longer need the wrapper object type.
In older versions of Realm you need an RLMObject which contains the string:
#interface StringObject : RLMObject
#property NSString *value;
#end
RLM_ARRAY_TYPE(StringObject)
#implementation StringObject
#end
#interface Object : RLMObject
#property RLMArray<StringObject> *array;
#end
Related
For some reason my RLMArray's are nil when I run my program.
I am able to see the data in the RLM browser, and it links appropriatley.
Is there something I could be missing here?
#interface HMFAlbum : RLMObject
#property NSInteger persistentId;
#property RLMArray<HMFTrack> *tracks;
#property RLMArray<HMFRange> *ranges;
#end
#interface HMFTrack : RLMObject
#property NSInteger persistentId;
#property HMFAlbum *album;
#end
RLM_ARRAY_TYPE(HMFTrack)
#interface HMFRange : RLMObject
#property NSInteger persistentId;
#property (readonly) RLMLinkingObjects *albums;
#end
RLM_ARRAY_TYPE(HMFRange)
It's expected that instance variables of persisted RLMObject instances will be nil as the property getters read values directly from the Realm file. The instance variables are only used for objects prior to being saved to the Realm, and remain nil after that point.
The Debugging section of the Realm documentation touches on this topic and mentions an LLDB script that can be used to show property values of persisted objects when debugging in Xcode. The -description method on the model classes, used by NSLog when formatting objects using the %# format specifier, will also show the property values as expected.
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
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.
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.
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