Subclass Class Method Override in CustomControls?

I have found a problem in my customcontrols I had not seen before. To make use of the UIView autoresizing features, I use subclasses that return a different value for the layerclass property. So I thought. In reality, all UIViews in my project return that layerclass until a new subclass is built – and then they carry this classes’ value.

It occured to me the usual class_addmethod and class_replacemethod ObjectiveCRuntime functions used for building custom subclasses do not work on class methods – they return true when I call them but the property of a subclass’ instance keeps the old value.
I then tried it with a method_setimplementation call and this works. But sadly this works on all calls of this class hierarchy, so the superclass changes its value too.

Do you have any hints? How can I change the value of a class method – or, better, override a declared class method successfully but only for this subclass?

class_addMethod and class_replaceMethod do work for class methods also. You need to change the meta class (= the class of the class).

Thanks, Eli! I tried, but apparently the wrong way. What metaclass changes do you mean? And change the class methods with what ObjectiveC Runtime method?

Oh, read your answer another few times and it occurs to me you mean I have to change the implementation on the meta class, not on the custom class I build? Will that be a unique meta class for this custom class? I thought it would be the same like its superclass’ metaclass.

EDIT: Still must be doing something wrong. After adding instance methods, I tried it with

[code]
objc_registerClassPair(result)
dim mymetaclassptr as ptr = ObjectiveCRuntime.objc_getMetaClass (ObjectiveCRuntime.class_getName(result))
dim mymetaclass as CString = ObjectiveCRuntime.class_getName (mymetaclassptr) // just to make sure it’s right in Debugger

//Now lets check the classmethods
if classmethods.Ubound > -1 then
for q as uinteger = 0 to classmethods.Ubound
dim method as TargetClassMethodHelper = classmethods (q)
dim SEL as Ptr = NSSelectorFromString (method.selName)
dim OriginalMethod as ptr = ObjectiveCRuntime.class_getClassMethod (mymetaclassptr, SEL)
if OriginalMethod <> NIL then
dim oldImplementation as Ptr = ObjectiveCRuntime.method_setImplementation (OriginalMethod, method.impl)
if oldImplementation = NIL then
dim err as new ErrorException
err.Reason = "no old implementation for method while replacing "+classmethods(q).selName
raise err
end if
end if
next
end if[/code]
And this still changes the property of the superclass (UIview) too. Do you have any idea where I err?
(With replacemethod or addmethod on the metaclass the method result stays the original one for both the superclass and the custom subclass, although addmethod returns true.)

Each class in the Objective C Runtime has a meta class. Why? In the Objective C Runtime each class is an instance of another class, the meta class. So classes are objects to.

That is also the reason why the functions are called objc_allocateClassPair and objc_registerClassPair. They register not only the class you are defining but also the meta class of that class.

Dim metaClassPtr As Ptr = objc_getMetaClass("YourClassName") Call class_addMethod(metaClassPtr, sel_registerName("aSelector:"), AddressOf SharedXojoMethod, "v@:@")
Note that objc_getMetaClass and class_addMethod are external methods since I don’t use and know MacOSLib.

Thanks, Eli. That’s what I tried but it doesn’t override the method, though class_addmethod returns true. Only way that worked is to exchange the implementation but that is global then.

No, you did something different – at least in your code above. For example:

ObjectiveCRuntime.class_getClassMethod (mymetaclassptr, SEL)

is wrong. You would need to use class_getInstanceMethod.

Try to translate my code into “MacOSLib”-code:

Dim metaClassPtr As Ptr = objc_getMetaClass("YourClassName") Call class_addMethod(metaClassPtr, sel_registerName("aSelector:"), AddressOf SharedXojoMethod, "v@:@")
More is not necessary. Get the meta class pointer and add the method.

As far as I can tell, that’s what I try. Therefore: Sorry for bothering you, Eli, but I’m not up to resolving this today, it seems.

The steps so far are:
I send this to an extended versin of Jason’s targetclasshelper:

   methods.Append new TargetClassMethodHelper("layerClass", AddressOf impl_layerClassGradient, "#@:",true, true)

(One of the Boolean ad the end is a flag for class methods)

Implementation of impl_layerClassGradient is simply

static mmyclass as ptr = NSClassFromString ("CAGradientLayer") return mmyclass

and then in the subclass creation method it’s (after registering the class as a subclass of UIView)

[code] objc_registerClassPair(result)

dim mymetaclassptr as ptr = ObjectiveCRuntime.objc_getMetaClass (ObjectiveCRuntime.class_getName(result))
dim mymetaclass as CString = ObjectiveCRuntime.class_getName (mymetaclassptr)

if classmethods.Ubound > -1 then
for q as uinteger = 0 to classmethods.Ubound
dim method as TargetClassMethodHelper = classmethods (q)
dim SEL as Ptr = NSSelectorFromString (method.selName)
dim success as boolean =ObjectiveCRuntime.class_addMethod (mymetaclassptr, SEL, method.impl, method.charCode.ToCString (StandardTextEncoding))
next
end if[/code]
But then layerClass is still CALayer. If your method works I must be doing something very silly which I don’t see.

Sorry, I can’t help you further. I don’t understand your code because I only work with direct declares into the Objective C Runtime.

Never mind, Eli. Thanks for your help. If you should ever have a declare that makes use of a class method override, would you mind sharing it? Currently I cannot solve this issue and will go with a workaround – attach a sublayer and a sublayers autoresize method to the View.