Cocoa delegates

  1. 2 weeks ago

    Wondering whats the best approach to implement delegates for Cocoa controls, classes. Any recommendations or examples will be greatly appreciated...

    Im doing the basic calling Obj-C to create a class for a delegate (with/out protocols) and creating corresponding instances, all inspired by macoslib, ioskit and other projects found online.

    Is it possible to uses instance methods as callbacks? (i only got it working with shared methods, when using instance methods the "ID" received was not the same (Ptr) of the delegate class instance I created in code)

    I ended up with a "delegateClass" wrapper that I subclass, with a dictionary to keep track of classes instances already created and the actual delegate instances with its corresponding weakRef pointing to its owner.

    I was looking on how to clean this dictionary, I notice that by the time I get the control "close" event or the destructor is invoked my instance Ptr is already null. I ended up running a ForEach every so often on the lifeCycle of delegateClass to look for Nil weakRef and removing them from the dictionary.

    For each delegate a control implements a separate class instance of "delegateClass", in general (most use-cases) in the callback (shared method) I end up calling a handler/method on the owner (weakref to control, canvas, etc). I tried implementing this using the actual control class (similar to how macoslib does it) with some helper functions to reduce the scaffolding but it was still quite a lot of work to repeat on each control/class (a bit ugly, the separate class made it cleaner). Is there anything else more elegant/reusable?

  2. Andrew L

    Feb 9 San Francisco, CA, USA

    @Jose C Is it possible to uses instance methods as callbacks?

    No. Instance methods are virtual, meaning there can be more than one implementation (i.e. method overriding) and the decision about which one to actually use is deferred until the method is actually invoked. Third party libraries don't know how to make that decision, or even that a decision is needed. Also, virtual methods receive a hidden first parameter that refers back to the instance (the me/self reference), meaning virtual methods can never satisfy the callback's signature.

  3. Christian S

    Feb 9 Pre-Release Testers, Xojo Pro, XDC Speakers Germany

    Are you sure we don't have such a class already in the MBS Plugins?

    Like we have a couple of delegate implementing classes.

  4. @Andrew L Also, virtual methods receive a hidden first parameter that refers back to the instance (the me/self reference)

    That explains a lot...

  5. @ChristianSchmitz Are you sure we don't have such a class already in the MBS Plugins?

    Christian I have not look at MBS yet

  6. Graham B

    Feb 9 Pre-Release Testers, Xojo Pro The Canada's

    Do protocols have to be registered to be able to assign them?

    objc_getProtocol("MTKViewDelegate") returns 0

    Dev Source

    I'm trying to set the delegate against MTKView. I registered a new subclass of NSObject with objc and added the methods with pointers to shared methods. The methods add successfully but once attached to the view the methods are never called.

    I have had this working before with other delegates on iOS but I'm wondering if the protocol not existing is a problem.

  7. For "MTKView " your protocol is "MTKViewDelegate", I think it should be something in the lines of:

    declare function NSClassFromString lib "Foundation" (name as CFStringRef) as Ptr
    declare function objc_allocateClassPair lib "Foundation" (superclass as Ptr, name as CString, extraBytes as Integer) as Ptr
    declare sub objc_registerClassPair lib "Foundation" (cls as Ptr)
    declare function class_addMethod lib "Foundation" (cls as Ptr, name as Ptr, imp as Ptr, types as CString) as Boolean
    declare function objc_getProtocol lib "Foundation" (name as CString) as Ptr
    declare function class_addProtocol lib "Foundation" (Cls as Ptr, protocol as Ptr) as Boolean
    dim className as text = "myMTKViewDelegate"
    dim protocolName as text = "MTKViewDelegate"
    dim myDelegateClass as Ptr = objc_allocateClassPair(NSClassFromString("NSObject"), className, 0)
    class_addProtocol (myDelegateClass, objc_getProtocol(protocolName))
  8. Graham B

    Feb 9 Pre-Release Testers, Xojo Pro The Canada's

    My problem is that objc_getProtocol(protocolName) returns 0 as it has not been loaded. Maybe I need to manually recreate the protocol.

  9. r u on testing on iOS, if so I found this on apple's forum, hope it helps...

    Whether or not you are able to use Metal APIs in a given target is dependent on the selected platform and SDK. As there is no Metal.framework (or MetalKit.framework, etc) for the iOS Simulator SDK, what you are describing should be impossible. Regardless of whether you're running OS X Yosemite or El Capitan, Metal is not supported in the Simulator.

  10. Graham B

    Feb 9 Pre-Release Testers, Xojo Pro The Canada's

    Running on macos 10.12

  11. Graham B

    Feb 9 Pre-Release Testers, Xojo Pro The Canada's
    Edited 2 weeks ago

    I have read that if the protocol is not referenced in source it will not be loaded into runtime.

    From another forum:

    Found the answer in the Apple docs:

    The compiler creates a protocol object for each protocol declaration it encounters, but only if the protocol is also:

    Adopted by a class,
    Or referred to somewhere in source code (using @protocol())

  12. @Jose C — RectControls being already implemented as Cocoa objects in Xojo, it is way easier to implement methods as extensions using the Handle, which has been done quite a bit in macoslib (see Additional Modules/Class Extensions).

    Of course, Cocoa controls which are not implemented in Xojo, like NSSearchField or NSTokenField, need to be created from scratch from a RectControl (usually a Canvas).

    About the implementation of delegates in Cocoa, I would advise you to at the NSSearchField implementation in macoslib. It creates a subclass of NSSearchField which includes the methods required by the delegate protocol. The reason is that actions are implemented as private methods so they are not accessible from another class like a "delegate (sub)class".

  13. Graham B

    Feb 11 Pre-Release Testers, Xojo Pro The Canada's

    If the protocol is missing you can manually build it yourself :)

    Private Shared Function RegisterProtocols() as integer
      //ensure MTKViewDelegate protocol exists
    dim cName as CString = "MTKViewDelegate"
    dim existing as integer = ObjectiveCRuntime.objc_getProtocol(cName)
    if existing <> 0 then 
    return  existing //all ok - found
    end if
    //does not exist so create it
    dim proto as integer = ObjectiveCRuntime.objc_allocateProtocol(cName)
    if proto = 0 then 
    //could not allocate name
    return 0
    end if
    dim sel as integer 
    dim types as CString
    //add the methods
    sel = NSSelectorFromString("mtkView:drawableSizeWillChange:")
    types = "v@:@{CGSize}"
    sel = NSSelectorFromString("drawInMTKView:")
    types = "v@:@"
    //register the protocol
    return ObjectiveCRuntime.objc_getProtocol(cName)
    End Function

    Then you can assign the protocol to your class as mentioned above

or Sign Up to reply!