Objective-C Xamarin.iOS의 선택기
언어는 Objective-C 선택기를 기반으로 합니다. 선택기는 개체 또는 클래스로 보낼 수 있는 메시지입니다. Xamarin.iOS 는 인스턴스 선택기를 인스턴스 메서드에 매핑하고 클래스 선택기를 정적 메서드에 매핑합니다.
일반 C 함수(C++ 멤버 함수와 같이)와 달리 P/Invoke를 사용하여 선택기를 직접 호출할 수 없습니다. 선택기는 다음을 사용하여 클래스 또는 인스턴스로 Objective-C 전송됩니다.objc_msgSend
함수.
메시지에 Objective-C대한 자세한 내용은 Apple의 개체 작업 가이드를 참조하세요.
예시
다음을 호출한다고 가정합니다. sizeWithFont:forWidth:lineBreakMode:
에 대한 선택기입니다.NSString
Apple 설명서의 선언은 다음과 같습니다.
- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode
이 API에는 다음과 같은 특성이 있습니다.
- 반환 형식은
CGSize
통합 API에 대한 것입니다. - 매개 변수
font
는 uifontnsobject에서 파생 된 형식 (간접적) 이며, 이는 System.IntPtr에 매핑됩니다. width
매개 변수인 aCGFloat
는 .에 매핑됩니다nfloat
.lineBreakMode
매개 변수는 이미 Xamarin.iOS에UILineBreakMode
/&I로 바인딩되었습니다.UILineBreakMode
열거형.
모두 합치면 선언이 objc_msgSend
일치해야 합니다.
CGSize objc_msgSend(
IntPtr target,
IntPtr selector,
IntPtr font,
nfloat width,
UILineBreakMode mode
);
다음과 같이 선언합니다.
[DllImport (Constants.ObjectiveCLibrary, EntryPoint="objc_msgSend")]
static extern CGSize cgsize_objc_msgSend_IntPtr_float_int (
IntPtr target,
IntPtr selector,
IntPtr font,
nfloat width,
UILineBreakMode mode
);
이 메서드를 호출하려면 다음과 같은 코드를 사용합니다.
NSString target = ...
Selector selector = new Selector ("sizeWithFont:forWidth:lineBreakMode:");
UIFont font = ...
nfloat width = ...
UILineBreakMode mode = ...
CGSize size = cgsize_objc_msgSend_IntPtr_float_int(
target.Handle,
selector.Handle,
font == null ? IntPtr.Zero : font.Handle,
width,
mode
);
반환된 값이 8바이트 미만의 구조체(예: 통합 API로 전환하기 전에 사용된 이전 SizeF
버전)였다면 위의 코드는 시뮬레이터에서 실행되었지만 디바이스에서 충돌했습니다. 크기가 8비트 미만인 값을 반환하는 선택기를 호출하려면 함수를 선언합니다 objc_msgSend_stret
.
[DllImport (MonoTouch.Constants.ObjectiveCLibrary, EntryPoint="objc_msgSend_stret")]
static extern void cgsize_objc_msgSend_stret_IntPtr_float_int (
out CGSize retval,
IntPtr target,
IntPtr selector,
IntPtr font,
nfloat width,
UILineBreakMode mode
);
이 메서드를 호출하려면 다음과 같은 코드를 사용합니다.
NSString target = ...
Selector selector = new Selector ("sizeWithFont:forWidth:lineBreakMode:");
UIFont font = ...
nfloat width = ...
UILineBreakMode mode = ...
CGSize size;
if (Runtime.Arch == Arch.SIMULATOR)
size = cgsize_objc_msgSend_IntPtr_float_int(
target.Handle,
selector.Handle,
font == null ? IntPtr.Zero : font.Handle,
width,
mode
);
else
cgsize_objc_msgSend_stret_IntPtr_float_int(
out size,
target.Handle, selector.Handle,
font == null ? IntPtr.Zero: font.Handle,
width,
mode
);
선택기 호출
선택기 호출에는 다음 세 가지 단계가 있습니다.
- 선택기 대상을 가져옵니다.
- 선택기 이름을 가져옵니다.
- 적절한 인수를 사용하여 호출
objc_msgSend
합니다.
선택기 대상
선택기 대상은 개체 인스턴스 또는 클래스입니다 Objective-C . 대상이 인스턴스이고 바인딩된 Xamarin.iOS 형식에서 온 경우 속성을 사용합니다 ObjCRuntime.INativeObject.Handle
.
대상이 클래스인 경우 클래스 인스턴스에 대한 참조를 가져오는 데 사용한 ObjCRuntime.Class
다음 속성을 사용합니다 Class.Handle
.
선택기 이름
선택기 이름은 Apple 설명서에 나열됩니다. 예를 들어 포함 NSString
sizeWithFont:
및 sizeWithFont:forWidth:lineBreakMode:
선택기입니다. 포함된 콜론과 후행 콜론은 선택기 이름의 일부이며 생략할 수 없습니다.
선택기 이름이 있으면 인스턴스를 ObjCRuntime.Selector
만들 수 있습니다.
통화 objc_msgSend
objc_msgSend
는 메시지(선택기)를 개체에 보냅니다. 이 함수 패밀리는 선택기 대상(인스턴스 또는 클래스 핸들), 선택기 자체 및 선택기에서 필요한 인수 등 두 개 이상의 필수 인수를 사용합니다. 인스턴스 및 선택기 인수는 System.IntPtr
모두 다시 기본 인수는 선택기에서 예상하는 형식(예nint
: 모든 파생 형식에 대한 int
인수)System.IntPtr
NSObject
과 일치해야 합니다. 사용NSObject.Handle
형식 인스턴스에 대한 Objective-C 속성을 IntPtr
가져옵니다.
두 objc_msgSend
개 이상의 함수가 있습니다.
- 구조체를 반환하는 선택기에 사용합니다
objc_msgSend_stret
. ARM에서는 열거형이 아닌 모든 반환 형식 또는 C 기본 제공 형식(char
,,short
,int
,long
float
,double
)이 포함됩니다. x86(시뮬레이터)에서 이 메서드는 크기가 8바이트보다 큰 모든 구조체(CGSize
8바이트이며 시뮬레이터에서는 사용되지 않음)에 사용해야objc_msgSend_stret
합니다. - x86에서만 부동 소수점 값을 반환하는 선택기에 사용합니다
objc_msgSend_fpret
. 이 함수는 ARM에서 사용할 필요가 없습니다. 대신 .objc_msgSend
- 기본 objc_msgSend 함수는 다른 모든 선택기에 사용됩니다.
호출해야 하는 objc_msgSend
함수(시뮬레이터 및 디바이스 각각에 다른 메서드가 필요할 수 있음)를 결정한 후에는 일반 [DllImport]
메서드를 사용하여 나중에 호출할 함수를 선언할 수 있습니다.
미리 만들어진 objc_msgSend
선언 집합은 .에서 ObjCRuntime.Messaging
찾을 수 있습니다.
시뮬레이터 및 디바이스에서 다른 호출
위에서 Objective-C 설명한 대로 세 가지 종류의 objc_msgSend
메서드가 있습니다. 하나는 일반 호출용이고, 하나는 부동 소수점 값을 반환하는 호출용(x86에만 해당) 및 구조체 값을 반환하는 호출용입니다. 후자에는 접미사가 _stret
포함됩니다 ObjCRuntime.Messaging
.
특정 구조체(아래에 설명된 규칙)를 반환하는 메서드를 호출하는 경우 반환 값을 가진 메서드를 첫 번째 매개 변수로 값으로 out
호출해야 합니다.
// The following returns a PointF structure:
PointF ret;
Messaging.PointF_objc_msgSend_stret_PointF_IntPtr (out ret, this.Handle, selConvertPointFromWindow.Handle, point, window.Handle);
메서드를 사용하는 _stret_
시기에 대한 규칙은 x86 및 ARM에 따라 다릅니다.
시뮬레이터와 디바이스 모두에서 바인딩이 작동하도록 하려면 다음과 같은 코드를 추가합니다.
if (Runtime.Arch == Arch.DEVICE)
{
PointF ret;
Messaging.PointF_objc_msgSend_stret_PointF_IntPtr (out ret, myHandle, selector.Handle);
return ret;
}
else
{
return Messaging.PointF_objc_msgSend_PointF_IntPtr (myHandle, selector.Handle);
}
objc_msgSend_stret 메서드 사용
ARM용으로 빌드할 때 다음을 사용합니다. objc_msgSend_stret
열거형이 아닌 값 형식 또는 열거형의 기본 형식(int
,, byte
, short
, long
, double
float
)의 경우
x86용으로 빌드할 때 objc_msgSend_stret
열거형이 아니거나 열거형의 기본 형식(int
, , byte
, short
, long
, double
float
)이 아니고 네이티브 크기가 8바이트보다 큰 값 형식의 경우
고유한 서명 만들기
필요한 경우 다음 요지를 사용하여 고유한 서명을 만들 수 있습니다.