'How do I port a Swift class along with it's extensions to C# for Xamarin iOS?
I'm trying to port AVFoundation code I wrote in Swift, to Xamarin iOS C# classes. I'm not great with Swift but the issue I have with it is pseudo multiple-inheritance pattern that I see with extensions.
Here's a class stub
class CaptureProcessor : NSObject {
let captureQueue = DispatchQueue(label: "com.AVFoundationCamera.CaptureProcessor.queue"
, qos: .utility)
let callbackParent : ImplementsCallback
init {}
}
and it's extension
extension CaptureProcessor : AVCapturePhotoCaptureDelegate {
func photoOutput(_ output: AVCapturePhotoOutput, willBeginCaptureFor resolvedSettings: AVCaptureResolvedPhotoSettings) {
self.callbackParent.willBeginCaptureForCallback(output: output, resolvedSettings: resolvedSettings)
}
}
How would I write these in C# for Xamarin iOS or MAUI, and reliably inherit the delegate call behaviour?
This works, but what's the pattern to inherit the delegate extension?
public class CaptureProcessor : NSObject { ... }
Solution 1:[1]
Do you need to copy this exact structure? Because a Swift extension is just a strategy to extend the definition of a class outside its initial definition.
For simplicity, you could "merge" all implementations of the extension in the original class definition. Using your example:
class CaptureProcessor : NSObject {
let captureQueue = DispatchQueue(label: "com.AVFoundationCamera.CaptureProcessor.queue"
, qos: .utility)
let callbackParent : ImplementsCallback
init {}
func photoOutput(_ output: AVCapturePhotoOutput, willBeginCaptureFor resolvedSettings: AVCaptureResolvedPhotoSettings) {
self.callbackParent.willBeginCaptureForCallback(output: output, resolvedSettings: resolvedSettings)
}
}
That is translated this into C# as:
using System;
using AVFoundation;
using CoreFoundation;
internal partial class CaptureProcessor : AVCapturePhotoCaptureDelegate
{
internal DispatchQueue captureQueue = new DispatchQueue("com.AVFoundationCamera.CaptureProcessor.queue");
internal IImplementsCallback callbackParent;
internal CaptureProcessor() : base() { }
internal CaptureProcessor(IntPtr handle) : base(handle) {}
public override void DidCapturePhoto(AVCapturePhotoOutput captureOutput, AVCaptureResolvedPhotoSettings resolvedSettings)
{
callbackParent.WillBeginCaptureForCallback(captureOutput, resolvedSettings);
}
}
Now, if you want to keep the definition separation, as the original Swift code, you could try to use C#'s Partial Classes:
using System;
using AVFoundation;
using CoreFoundation;
internal partial class CaptureProcessor : AVCapturePhotoCaptureDelegate
{
internal DispatchQueue captureQueue = new DispatchQueue("com.AVFoundationCamera.CaptureProcessor.queue");
internal IImplementsCallback callbackParent;
internal CaptureProcessor() : base() { }
internal CaptureProcessor(IntPtr handle) : base(handle) {}
}
internal partial class CaptureProcessor
{
public override void DidCapturePhoto(AVCapturePhotoOutput captureOutput, AVCaptureResolvedPhotoSettings resolvedSettings)
{
callbackParent.WillBeginCaptureForCallback(captureOutput, resolvedSettings);
}
}
Note: Given that AVCapturePhotoCaptureDelegate is a class on Xamarin.iOS and not an interface, all partial class definition needs to be a child of AVCapturePhotoCaptureDelegate.
=== Edit to include comments explanations ===
Multiple inheritances will depend on how Xamarin.iOS translates the UIKit/Foundation class into C#. If 2 elements are classes in Xamarin (like NSObject and AVCapturePhotoCaptureDelegate), you will have to go with the "lower" level as the base class. If you have multiple protocols/interfaces, it is just a "regular" C# interface conformance.
The "issue" with AVCapturePhotoCaptureDelegate here is how Xamarin.iOS translates Objective-C protocols. Many protocols in UIKit have to be applied to NSObject. While they are constrained protocols in Objective-C/Swift, C# does not have the same constraint rules, so they are translated to Xamarin as Classes, preventing multiple conformance.
When looking at Apple's documentation, any object that extends NSObjectProtocol will be translated to Xamarin.iOS as a class, child of NSObject. Using the same AVKit class as an example:
public protocol AVCapturePhotoCaptureDelegate : NSObjectProtocol
So it is translated to Xamarin.iOS as:
public class AVCapturePhotoCaptureDelegate : NSObject
The trick here would be to, first, check if the Swift class is constrained to NSObjectProtocol. For these cases, you can be sure that you can only inherit the lower as the base class since Xamarin.iOS will convert those as a class, even if they are protocols (interfaces) on the native world.
For other cases, check if the protocol was translated into Xamarin's interfaces. If the interface is kept you can use Partial classes to have the same implementation structure as in Swift.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
