Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RLMObject as a parent parent class #652

Closed
SebastianThiebaud opened this issue Jul 22, 2014 · 6 comments
Closed

RLMObject as a parent parent class #652

SebastianThiebaud opened this issue Jul 22, 2014 · 6 comments

Comments

@SebastianThiebaud
Copy link

Hello,

It looks like RLMObject isn't ready to be parent parent of class. It might be not clear, let me explain:

We have a class called ESObject with a lot of features on it. A lot of models inherit of ESObject. As we want use Realm, we use this parenting system:
RMLObject > ESObject > model (ex: ESDiscussion, ESPost, ESComment,...).

The problem is when we want to set a model property, we got this crash:

 *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[RLMStandalone_ESObject setName:]: unrecognized selector sent to instance 0x10b00fdc0'
@alazier
Copy link
Contributor

alazier commented Jul 22, 2014

This is a known limitation - we currently only support object which derive directly from RLMObject. The exception message should have explained this (which in your case it obviously doesn't) - we should be able to get the error message fixed pretty quickly so other people don't suffer from the same confusion.

I hope we will be able to support multiple levels of subclassing in the future - it adds some complexity to the apis and implementation, but I hope we can revisit supporting this after addressing the easier/smaller issues that have been reported since launch.

@SebastianThiebaud
Copy link
Author

Do you think moving the ESObject's code into a category of RMLObject is a good idea?

@alazier
Copy link
Contributor

alazier commented Jul 22, 2014

I don't see why that wouldn't work.

@jpsim
Copy link
Contributor

jpsim commented Jul 22, 2014

@SebastienThiebaud just be aware that if you add properties to RLMObject through a category using associated objects, those won't be persisted by Realm.

@ghost
Copy link

ghost commented Aug 6, 2014

@SebastienThiebaud You can add persisted properties in RLMObject category if you add the properties at runtime before first RLMObject is initialized (for example by filtering the objc_getClassList to subclasses of RLMObject).

example call:

[Class addProperty:@"syncUpdated" Type:@"@\"NSDate\""];
#import "RLMObject+Sync.h"
#import <objc/runtime.h>

@implementation RLMObject (Sync)
@dynamic associatedObject;

NSString *getter(id self, SEL _cmd) {
    return objc_getAssociatedObject(self, @selector(associatedObject)) ;
}

void setter(id self, SEL _cmd, id value) {
    objc_setAssociatedObject(self, @selector(associatedObject), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC) ;
}

+ (void)addProperty:(NSString *)propertyName Type:(NSString *)propertyType
{
    //add properties
    objc_property_attribute_t type = { "T", [propertyType UTF8String]};
    objc_property_attribute_t ownership = { "&", "" };
    objc_property_attribute_t attrs[] = { type, ownership };

    class_addProperty(self, [propertyName UTF8String], attrs, 2);
    class_addMethod(self, NSSelectorFromString(propertyName), (IMP)getter, "@@:");
    class_addMethod(self, NSSelectorFromString([NSString stringWithFormat:@"set%@:", [propertyName capitalizedString]]), (IMP)setter, "v@:@");

}

- (instancetype)initWithSync
{
    //you have to get property names here, because init changes class
    unsigned int propertyCount;
    objc_property_t *properties = class_copyPropertyList([self class], &propertyCount);

    //init has to be called on self to create standalone class
    self = [self init];
    if (self) {
        //default value of property
        for (int i = 0; i < propertyCount; i++) {
            NSString *propertyName = [NSString stringWithCString:property_getName(properties[i]) encoding:NSUTF8StringEncoding];

            //example
            if ([propertyName isEqualToString:@"syncUpdated"]) {
                [self performSelector:NSSelectorFromString([NSString stringWithFormat:@"set%@:", [propertyName capitalizedString]]) withObject:[NSDate date]];
            }
        }

    }

    return self;
}

@end

@alazier
Copy link
Contributor

alazier commented Sep 29, 2014

This should now be possible on master with #940.

@alazier alazier closed this as completed Sep 29, 2014
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 18, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants