In my exploration of declares I have come to another question:
Doing the declares and creating a system object is fairly easy once one has got the basics.
But sometimes it is needed to catch their internal draw methods or forward an event to the Xojo instance that handles it.
What I believe to understand that far:
You cannot tweak the methods in a system class but have to set up an own subclass of it.
So I start with a branch in the constructor:
if SubClass = NIL then // create a global subclass first
dim objectClass As ptr=NSClassFromString(ClassName)
declare function objc_allocateClassPair lib "libobjc.dylib" (superclass as Ptr, name as CString, extraBytes as Integer) as Ptr
subclass = objc_allocateClassPair (objectClass, SubClassName, 0)
That works so far. Next would be to add own methods for superclass methods and events I want to handle myself.
Far as I found out this should be possible somehow with something like:
[code]Function class_replacemethod (aclass as ptr, name as cfstringref, method as ptr, types as cstring) As ptr
//used to tweak an event or method call to a personal one:
declare function class_replaceMethod lib “libobjc.dylib” (cls as ptr, name as Ptr, imp as Ptr, types as CString) as ptr
return class_replaceMethod (aclass ,NSSelectorFromString(name), method, types)
declare sub objc_registerClassPair lib "libobjc.dylib" (cls as Ptr)
dim res as ptr = class_replaceMethod (subclass, OriginalMethodName, AddressOf myMethod, "v@:")
but that’s where I fail. res returns NIL.
Could someone of you point me to an understandable reference on the C parameter types that “v@:” etc. ? Google has left me alone with thator everything I could find was too cryptic.
And do I have to do something different if it’s a method or a Notification/ Event handler? Do I have to address the delegate (or create one) in order for this to work?
Thanks a lot!
You need the correct type encodings. See here
the way it works is
so a function that takes an integer and returns a boolean would have types of “B@:i”
and the Xojo declaration would be like
function myHandler (targetObject as ptr, selector as ptr, param1 as integer) as boolean
The function you use to replace the class method has to be a shared method, so you’ll need to keep a dictionary of references when you create instances of the subclass.
dim newinstance as ptr=init(alloc(mysubclass))
Then you can rereference the Xojo control/class to the objC class instance using the “targetObject” parameter I mentioned above.
You can cast the value back to your Xojo class and call methods inside it.
*Be sure to hold the reference to the newly created subclass in a shared property and reuse it. If you try to create a new subclass with the same name, it will crash.
I’ve always used class_addMethod. What do you need class_replaceMethod for?
class_addMethod only adds the method if doesn’t already exist. class_replaceMethod adds it or replaces the existing implementation.
Once again thanks a lot, Jim!
That was the table I was looking for
That targetObject handling looks still a bit mind-bending, but somehow I get used to that feeling.
A method_exchangeimplementation would not work on the instance?
Don’t worry, it makes sense if you think of it like, “OK I have an instance of this new NSObject, now in the event handler, I can’t access my Xojo class… hmm we need to keep a reference table to lookup our Xojo class instance based on the NSObject instance…”
Another thing that’s good to know, is that when a class calls for a delegate, just create a subclass of NSObject and add the required methods. Then you can give that NSObject to the class that wants a delegate.
You need to use class_addMethod and not class_replaceMethod to override a method of the super class in your subclass (which is what you want to do in your case).
From my experience there is no need to specifiy the type encoding - I always used an empty string and I never encountered any problems with it.
And yes, you need a way to keep track of the Xojo instance / ObjC instance relations. I use a dictionary for that.