I've been plaing with 'objc_runtime' this weekend, and wanted to show how I 
created a subclass of NSObject with methods, property, and iVar.

Idea came from this`StackOverflow post 
<https://stackoverflow.com/questions/7819092/how-can-i-add-properties-to-an-object-at-runtime/7834787#7834787>`
    
    
    import objc_runtime
    import darwin / foundation
    from math import log2
    
    type
        propertyArray = array[3, objc_property_attribute_t]
    
    var
        prop_type = objc_property_attribute_t(name: "T", value: "@\"NSString\"")
        ownership = objc_property_attribute_t(name: "C", value: "")
        backingivar = objc_property_attribute_t(name: "V",value: "_privateName")
    
    let attrs:propertyArray = [prop_type, ownership, backingivar]
    
    
    objcr:
        # **********************************************
        # ***** DYNAMIC CLASS CREATION BEGINS HERE *****
        # **********************************************
        proc nameGetter(self: ID, cmd: SEL ): NSString =
            var ivar = getIvar(cast[Class]([SomeClass class]), "_privateName")
            result = cast[NSString](getIvar(self, ivar))
        
        proc nameSetter(self: ID, cmd: SEL, newName: NSString ) =
            var ivar = getIvar(cast[Class]([SomeClass class]), "_privateName")
            setIvar(self, ivar, [newName.ID copy])
        
        # *****************************
        # ***** SUBCLASS NSOBJECT *****
        # *****************************
        let SomeClass = allocateClassPair(getClass("NSObject"),"SomeClass",0)
        
        # *******************************************************************
        # ***** ivars can only be added PRIOR to registering the class! *****
        # *******************************************************************
        discard 
addIvar(SomeClass,"_privateName",sizeof(ID),log2(sizeof(ID).float).int,"@")
        
        # *****************************
        # ***** REGISTER SUBCLASS *****
        # *****************************
        registerClassPair(SomeClass)
        
        # 
*****************************************************************************
        # ***** Properties/Methods can only be added AFTER registering the 
class! *****
        # 
*****************************************************************************
        discard addProperty(cast[Class]([SomeClass class]), "name", attrs)
        discard addMethod(getClass("SomeClass"),registerName("name"), 
cast[IMP](nameGetter), "@@:")
        discard addMethod(getClass("SomeClass"),registerName("setName:"), 
cast[IMP](nameSetter), "v@:@")
        # ********************************************
        # ***** DYNAMIC CLASS CREATION ENDS HERE *****
        # ********************************************
        
        proc main() =
            var o = [SomeClass new]
            [o setName: @"Steve"]
            NSLog("%@",[o name])
            [o setName: @"Jobs"]
            NSLog("%@",[o name])
    
    if isMainModule:
        main()
    
    
    Run

AIR.

Reply via email to