標準ライブラリで定義済みのデリゲートは、プロトコルと一緒に利用されます。
プロトコルは、C#の世界のインターフェースとほぼ同じと考えていただいて結構です。iOSの世界では、標準ライブラリに様々なプロトコルが定義されています。
では、標準ライブラリのプロトコルを利用したデリゲートの実装を詳しく見ていきましょう。
今回は写真撮影のサンプルアプリを題材にします。
以下よりサンプルコードをダウンロードして下さい。
developer.apple.com
その中の、PhotoCaptureDelegate.swift
ファイルのコードを見てみましょう。
クラスの定義部分に注目すると、
class PhotoCaptureProcessor: NSObject {
extension PhotoCaptureProcessor: AVCapturePhotoCaptureDelegate {
とあります。
ここに出てきているAVCapturePhotoCaptureDelegate
は定義済みのプロトコルです。
Swift でAVCapturePhotoCaptureDelegate
のように定義済みのプロトコルが利用されている場合、基本的には Xamarin.iOS 側には対応する interface および class が準備されています。
interface は Swift のプロトコルの名前の頭に 「I」 を付けた名前、class は Swift の Protocol の名前と同名になっています。
例えば、Swift のAVCapturePhotoCaptureDelegate
に対応する Xamarin.iOS の interface はIAVCapturePhotoCaptureDelegate
、class はAVCapturePhotoCaptureDelegate
です。
では、IAVCapturePhotoCaptureDelegate
のメタ情報を見てみましょう
namespace AVFoundation
{
[Introduced(PlatformName.iOS, 10, 0, PlatformArchitecture.None, null)]
[Protocol(Name = "AVCapturePhotoCaptureDelegate", WrapperType = typeof(AVCapturePhotoCaptureDelegateWrapper))]
[ProtocolMember(IsRequired = false, IsProperty = false, IsStatic = false, Name = "WillBeginCapture", Selector = "captureOutput:willBeginCaptureForResolvedSettings:", ParameterType = new[] { typeof(AVCapturePhotoOutput), typeof(AVCaptureResolvedPhotoSettings) }, ParameterByRef = new[] { false, false })]
[ProtocolMember(IsRequired = false, IsProperty = false, IsStatic = false, Name = "WillCapturePhoto", Selector = "captureOutput:willCapturePhotoForResolvedSettings:", ParameterType = new[] { typeof(AVCapturePhotoOutput), typeof(AVCaptureResolvedPhotoSettings) }, ParameterByRef = new[] { false, false })]
[ProtocolMember(IsRequired = false, IsProperty = false, IsStatic = false, Name = "DidCapturePhoto", Selector = "captureOutput:didCapturePhotoForResolvedSettings:", ParameterType = new[] { typeof(AVCapturePhotoOutput), typeof(AVCaptureResolvedPhotoSettings) }, ParameterByRef = new[] { false, false })]
[ProtocolMember(IsRequired = false, IsProperty = false, IsStatic = false, Name = "DidFinishProcessingPhoto", Selector = "captureOutput:didFinishProcessingPhotoSampleBuffer:previewPhotoSampleBuffer:resolvedSettings:bracketSettings:error:", ParameterType = new[] { typeof(AVCapturePhotoOutput), typeof(CMSampleBuffer), typeof(CMSampleBuffer), typeof(AVCaptureResolvedPhotoSettings), typeof(AVCaptureBracketedStillImageSettings), typeof(NSError) }, ParameterByRef = new[] { false, false, false, false, false, false })]
[ProtocolMember(IsRequired = false, IsProperty = false, IsStatic = false, Name = "DidFinishProcessingRawPhoto", Selector = "captureOutput:didFinishProcessingRawPhotoSampleBuffer:previewPhotoSampleBuffer:resolvedSettings:bracketSettings:error:", ParameterType = new[] { typeof(AVCapturePhotoOutput), typeof(CMSampleBuffer), typeof(CMSampleBuffer), typeof(AVCaptureResolvedPhotoSettings), typeof(AVCaptureBracketedStillImageSettings), typeof(NSError) }, ParameterByRef = new[] { false, false, false, false, false, false })]
[ProtocolMember(IsRequired = false, IsProperty = false, IsStatic = false, Name = "DidFinishRecordingLivePhotoMovie", Selector = "captureOutput:didFinishRecordingLivePhotoMovieForEventualFileAtURL:resolvedSettings:", ParameterType = new[] { typeof(AVCapturePhotoOutput), typeof(NSUrl), typeof(AVCaptureResolvedPhotoSettings) }, ParameterByRef = new[] { false, false, false })]
[ProtocolMember(IsRequired = false, IsProperty = false, IsStatic = false, Name = "DidFinishProcessingLivePhotoMovie", Selector = "captureOutput:didFinishProcessingLivePhotoToMovieFileAtURL:duration:photoDisplayTime:resolvedSettings:error:", ParameterType = new[] { typeof(AVCapturePhotoOutput), typeof(NSUrl), typeof(CMTime), typeof(CMTime), typeof(AVCaptureResolvedPhotoSettings), typeof(NSError) }, ParameterByRef = new[] { false, false, false, false, false, false })]
[ProtocolMember(IsRequired = false, IsProperty = false, IsStatic = false, Name = "DidFinishCapture", Selector = "captureOutput:didFinishCaptureForResolvedSettings:error:", ParameterType = new[] { typeof(AVCapturePhotoOutput), typeof(AVCaptureResolvedPhotoSettings), typeof(NSError) }, ParameterByRef = new[] { false, false, false })]
[Unavailable(PlatformName.WatchOS, PlatformArchitecture.All, null)]
[Unavailable(PlatformName.TvOS, PlatformArchitecture.All, null)]
[Unavailable(PlatformName.MacOSX, PlatformArchitecture.All, null)]
public interface IAVCapturePhotoCaptureDelegate : INativeObject, IDisposable
{
}
}
かなりごちゃごちゃしていますが、悲しいことに全て非常に重要な情報です(笑)。特にName
やSelector
などの情報に注目してください。
次に、AVCapturePhotoCaptureDelegate
のメタ情報を見てみましょう
namespace AVFoundation
{
[Introduced(PlatformName.iOS, 10, 0, PlatformArchitecture.None, null)]
[Model]
[Protocol]
[Register("AVCapturePhotoCaptureDelegate", false)]
[Unavailable(PlatformName.WatchOS, PlatformArchitecture.All, null)]
[Unavailable(PlatformName.TvOS, PlatformArchitecture.All, null)]
[Unavailable(PlatformName.MacOSX, PlatformArchitecture.All, null)]
public class AVCapturePhotoCaptureDelegate : NSObject, IAVCapturePhotoCaptureDelegate, INativeObject, IDisposable
{
[CompilerGenerated]
[EditorBrowsable(EditorBrowsableState.Advanced)]
[Export("init")]
public AVCapturePhotoCaptureDelegate();
[CompilerGenerated]
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected AVCapturePhotoCaptureDelegate(NSObjectFlag t);
[CompilerGenerated]
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected internal AVCapturePhotoCaptureDelegate(IntPtr handle);
[CompilerGenerated]
[Export("captureOutput:didCapturePhotoForResolvedSettings:")]
public virtual void DidCapturePhoto(AVCapturePhotoOutput captureOutput, AVCaptureResolvedPhotoSettings resolvedSettings);
[CompilerGenerated]
[Export("captureOutput:didFinishCaptureForResolvedSettings:error:")]
public virtual void DidFinishCapture(AVCapturePhotoOutput captureOutput, AVCaptureResolvedPhotoSettings resolvedSettings, NSError error);
[CompilerGenerated]
[Export("captureOutput:didFinishProcessingLivePhotoToMovieFileAtURL:duration:photoDisplayTime:resolvedSettings:error:")]
public virtual void DidFinishProcessingLivePhotoMovie(AVCapturePhotoOutput captureOutput, NSUrl outputFileUrl, CMTime duration, CMTime photoDisplayTime, AVCaptureResolvedPhotoSettings resolvedSettings, NSError error);
[CompilerGenerated]
[Export("captureOutput:didFinishProcessingPhotoSampleBuffer:previewPhotoSampleBuffer:resolvedSettings:bracketSettings:error:")]
public virtual void DidFinishProcessingPhoto(AVCapturePhotoOutput captureOutput, CMSampleBuffer photoSampleBuffer, CMSampleBuffer previewPhotoSampleBuffer, AVCaptureResolvedPhotoSettings resolvedSettings, AVCaptureBracketedStillImageSettings bracketSettings, NSError error);
[CompilerGenerated]
[Export("captureOutput:didFinishProcessingRawPhotoSampleBuffer:previewPhotoSampleBuffer:resolvedSettings:bracketSettings:error:")]
public virtual void DidFinishProcessingRawPhoto(AVCapturePhotoOutput captureOutput, CMSampleBuffer rawSampleBuffer, CMSampleBuffer previewPhotoSampleBuffer, AVCaptureResolvedPhotoSettings resolvedSettings, AVCaptureBracketedStillImageSettings bracketSettings, NSError error);
[CompilerGenerated]
[Export("captureOutput:didFinishRecordingLivePhotoMovieForEventualFileAtURL:resolvedSettings:")]
public virtual void DidFinishRecordingLivePhotoMovie(AVCapturePhotoOutput captureOutput, NSUrl outputFileUrl, AVCaptureResolvedPhotoSettings resolvedSettings);
[CompilerGenerated]
[Export("captureOutput:willBeginCaptureForResolvedSettings:")]
public virtual void WillBeginCapture(AVCapturePhotoOutput captureOutput, AVCaptureResolvedPhotoSettings resolvedSettings);
[CompilerGenerated]
[Export("captureOutput:willCapturePhotoForResolvedSettings:")]
public virtual void WillCapturePhoto(AVCapturePhotoOutput captureOutput, AVCaptureResolvedPhotoSettings resolvedSettings);
}
}
こちらにも、非常に重要な情報が含まれています。先ほどのIAVCapturePhotoCaptureDelegate
のName
やSelector
などの情報と、こちらのExport
の情報を組み合わせて、コンパイル時にiOSのデリゲートが構成される仕組みになっています。深堀してみるとかなりの力技ですね(笑)
長くなりますので今回はここまでにします。
間違いなどございましたらご指摘お願いします。
次回は、具体的にデリゲートを含むコードをどう移植するのかご説明します。
次回はこちらからどうぞ!
hiro128.hatenablog.jp