Delegate problem

It‘s the first time I need to use a Xojo delegate in iOS; or rather in general. So I wonder if I’m ding something really stupid here:

In an iOS class, I created a delegate:

Protected Delegate Sub PaintMethodDelegate(w as double, h as double)

In a shared method of the same class, I use it (aSize is a NSSize structure):

Shared Function ImageFromContext(asize as FoundationFrameWork.nssize, paintmethod as ptr, opaque as boolean = false, scale as double = 1) As AppleImage if scale = 0 then scale = AppleScreen.MainScreen.Scale AppleCGContext.BeginImageContext(asize, opaque, Scale) dim sp as new PaintMethodDelegate (paintmethod) sp.Invoke (asize.width, asize.height) dim result as appleimage = AppleCGContext.Getimage AppleCGContext.EndImageContext return result End Function

And in the draw event of a view, I use the method:

dim pic as AppleImage = AppleImage.ImageFromContext (FoundationFrameWork.nsmakesize(300,450), AddressOf contextpaint) pic.DrawAtPoint FoundationFrameWork.NSMakePoint (20,20)

Where contextpaint is

[code]Sub Contextpaint(w as double, h as double)
system.debuglog w.ToText
system.debuglog h.ToText

dim context as AppleCGBitmapContext = AppleCGBitmapContext.CurrentContext
dim p as AppleBezierPath = AppleBezierPath.PathWithOval (FoundationFrameWork.NSMakeRect (0,0,context.Width, context.height))
p.FillWithBlendMode (CoreGraphicsFramework.CGBlendMode.Multiply, 0.6)
End Sub[/code]

w and h are defined and not 0 in the imagefromContext method, but in contextpaint they are always 0.
I can retrieve w and h anyway by the current context, but it would be much nicer to forward them. From the documentation, I thought this should work – it doesn’t. What am I doing wrong?

Also strange that the method does not work if I remove all the properties from delegate, method and Contextpaint method – it crashes then.

This won’t resolve your issue, but you could change the parameter from Ptr to PaintMethodDelegate:

Shared Function ImageFromContext(asize as FoundationFrameWork.nssize, paintmethod as PaintMethodDelegate, opaque as boolean = false, scale as double = 1) As AppleImage if scale = 0 then scale = AppleScreen.MainScreen.Scale AppleCGContext.BeginImageContext(asize, opaque, Scale) // dim sp as new PaintMethodDelegate (paintmethod) – remove this line paintmethod.Invoke (asize.width, asize.height) // change sp to paintmethod dim result as appleimage = AppleCGContext.Getimage AppleCGContext.EndImageContext return result End Function

You’re wrong, Eli – that fixed it! Thanks a lot!
I wasn’t aware I could define the delegate that way. Much better, thanks again!

I’d love to see the crash log.

This seems to be connected with me passing the method instance as ptr instead of PaintMethodDelegate. Still want to see the logs (which means: Should it have worked this way too)?

Yes, it sounds reasonable at first glance that this should work.

Glad to hear that! Thought so too, according to the documentation. Looks like it tried to jump a bit low in its memory:

System Integrity Protection: enabled

Crashed Thread: 0 Dispatch queue:

Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000050

VM Regions Near 0x50:
__TEXT 0000000000001000-0000000000215000 [ 2128K] r-x/rwx SM=COW /Users/USER/Library/Developer/CoreSimulator/Devices/C4AA2C05-0FE4-47C9-94F2-CC94E045E3E5/data/Containers/Bundle/Application/BEF0F75B-FA49-4FC9-9A94-4B9E39C34056/iOSLib Unified.debug

Application Specific Information:
CoreSimulator 201.3 - Device: iPhone 5s - Runtime: iOS 9.2 (13C75) - DeviceType: iPhone 5s

Thread 0 Crashed:: Dispatch queue:
0 rbframework.dylib 0x002ec7e0 RuntimeLockObject + 10
1 com.satzservice.ioslibunified 0x001e4bb6 View2.View2.Contextpaint%%o<View2.View2> + 95
2 com.satzservice.ioslibunified 0x00158bf4 Delegate.Invoke%% + 34
3 com.satzservice.ioslibunified 0x001731fe AppleImage.!ImageFromContext%o%t<FoundationFrameWork.NSSize>pbf8 + 525
4 com.satzservice.ioslibunified 0x001e46ca View2.View2.iOSLIbCanvas1_Draw%%o<View2.View2>oo<xojo.Core.Rect> + 3127
5 com.satzservice.ioslibunified 0x001e5068 Delegate.IM_Invoke%%oo<xojo.Core.Rect> + 93
6 com.satzservice.ioslibunified 0x001e50b4 AddHandler.Stub.21%%o<xojo.Core.Rect> + 64
7 com.satzservice.ioslibunified 0x001ec7b3 iOSLIbCanvas.informOnDrawRect%%ot<FoundationFrameWork.NSRect> + 212
8 com.satzservice.ioslibunified 0x00143df9 AppleView.informonDrawRect%%ot<FoundationFrameWork.NSRect> + 329
9 com.satzservice.ioslibunified 0x001428a1 AppleView.!impl_DrawRect32%%ppt<FoundationFrameWork.NSRect32Bit> + 445
10 0x006179db -[UIView(CALayerDelegate) drawLayer:inContext:] + 513
11 0x02a43366 -[CALayer drawInContext:] + 279
12 0x02a431fb backing_callback(CGContext*, void*) + 96
13 0x029203bd CABackingStoreUpdate_ + 2539
14 0x02a43193 __ZN2CA5Layer8display_Ev_block_invoke + 93
15 0x02a7c934 x_blame_allocations + 15
16 0x02a42ff2 CA::Layer::display
() + 1560
17 0x02a4324a -[CALayer _display] + 33
18 0x02a429d2 CA::Layer::display() + 142
19 0x02a43224 -[CALayer display] + 33
20 0x02a372d8 CA::Layer::display_if_needed(CA::Transaction*) + 326
21 0x02a3735e CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 38
22 0x02a29e8b CA::Context::commit_transaction(CA::Transaction*) + 317
23 0x02a5de03 CA::Transaction::commit() + 561
24 0x02a5e6c4 CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 92
26 0x01c97f5e __CFRunLoopDoObservers + 398
27 0x01c8d108 CFRunLoopRunSpecific + 504
28 0x01c8cefb CFRunLoopRunInMode + 123
29 0x00546206 -[UIApplication _run] + 540
30 0x0054bbfa UIApplicationMain + 160
31 rbframework.dylib 0x00337265 0x2d6000 + 397925
32 com.satzservice.ioslibunified 0x00002a92 xojo._RuntimeRun + 28
33 com.satzservice.ioslibunified 0x001ff285 _Main + 258
34 com.satzservice.ioslibunified 0x001feda1 main + 36
35 libdyld.dylib 0x02c50a21 start + 1

I think if Contextpaint would be a shared and not an instance method it might work.

This is more or less the problem.

Creating a delegate from an instance method holds a reference to the target object and when the delegate is invoked, the instance is passed into the function as ‘self’. By converting the delegate to a pointer your code is throwing away the object and the fact that it was an instance method. When the pointer is converted back into a delegate and invoked, the delegate simply can’t invoke the method correctly and things crash.

In a future release, I hope to make this raise an exception upon the conversion from an instance method to a pointer. There is absolutely nothing useful that can be done with that pointer, as far as I’ve seen.

I see. Thx, Joe & Eli! As written above, I overread the possibility to forward the parameter as a PaintMethodDelegate – from the LR (or the part of it I read) I had the feeling a ptr would be right. Anyway, everything’s fine now and I won’t forget the delegate parameter. For some time, at least :wink: