Search code examples
objective-cobjective-c-blocks

is it possible to set readonly properties within init-called blocks?


I'm using the builder pattern to do something like this

- (instancetype)initUsingBlock:(void(^)(id mutableCopy))block
{
    self = [super init];
    if (self && block)
    {
        __block id mutableInstance = [self mutableCopy];
        block(mutableInstance);
        self = [mutableInstance copy];
    }
    return self;
}

and setting properties using blocks. I'm doing this with the intention of not having to rewrite an init for every subclass of this one. But those properties are readonly and trying to set them within the block - called in another class - raises errors. Is there a right way to do this? __block doesn't seem to make a difference here.

EDIT: So, because of a comment down here, i became aware that it is not really a good idea to continue with what i was trying to do, so i dropped the builder pattern altogether, but i still wan't to know if it would be possible.


Solution

  • Yes you can do it using [setValue:forKey:] method of NSObject, but actually it's not a good practice doing that:

    @interface TestClass : NSObject
    
    @property (copy, nonatomic,readonly) NSString *testProperty;
    
    @end
    
    @implementation TestClass
    
    - (instancetype)initUsingBlock:(void(^)(id instance))block {
        if (self = [super init]) {
            block(self);
        }
        return self;
    }
    
    @end
    

    ...

    TestClass *test = [[TestClass alloc] initUsingBlock:^(id instance) {
        if ([instance respondsToSelector:@selector(testProperty)]) {
            [instance setValue:@"It's working" forKey:@"testProperty"];
        }
    }];
    NSLog(@"%@", test.testProperty);
    

    Or:

    TestClass *test = [[TestClass alloc] init];
    if ([test respondsToSelector:@selector(testProperty)]) {
        [test setValue:@"It's working" forKey:@"testProperty"];
    }
    

    PS: It works for all types inherited from NSObject or type which conforms NSKeyValueCoding protocol only.