Share via


Objective-C Xamarin.iOS'ta seçiciler

Dil Objective-C seçicileri temel alır. Seçici, bir nesneye veya sınıfa gönderilebilen bir iletidir. Xamarin.iOS , örnek seçicilerini örnek yöntemlerine, sınıf seçicileri ise statik yöntemlere eşler.

Normal C işlevlerinden (ve C++ üye işlevleri gibi) farklı olarak, bunun yerine P/Invoke kullanarak doğrudan bir seçici çağıramazsınız , seçiciler kullanılarak bir Objective-C sınıfa veya örneğe gönderilir objc_msgSend Işlev.

içindeki Objective-Ciletiler hakkında daha fazla bilgi için Apple'ın Nesnelerle Çalışma kılavuzuna göz atın.

Örnek

şunu çağırmak istediğinizi varsayalım: sizeWithFont:forWidth:lineBreakMode: seçicisi üzerinde NSString. Bildirim (Apple'ın belgelerinden) şöyledir:

- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode

Bu API aşağıdaki özelliklere sahiptir:

  • Dönüş türü Birleşik API'ye yöneliktir CGSize .
  • font parametresi, NSObject'ten türetilen bir UIFont (ve (dolaylı) türüdür ve System.IntPtr ile eşlenir.
  • width parametresi ile CGFloateşlenirnfloat.
  • lineBreakMode parametresi, UILineBreakModeXamarin.iOS'ta zatenUILineBreakMode Numaralandırma.

Hepsini bir araya getirmek için bildirimin eşleşmesi objc_msgSend gerekir:

CGSize objc_msgSend(
    IntPtr target,
    IntPtr selector,
    IntPtr font,
    nfloat width,
    UILineBreakMode mode
);

Bunu aşağıdaki gibi bildirin:

[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
);

Bu yöntemi çağırmak için aşağıdaki gibi bir kod kullanın:

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
);

Döndürülen değerin boyutu 8 bayttan küçük bir yapı olsaydı (Birleşik API'lere geçmeden önce kullanılan eski SizeF gibi), yukarıdaki kod simülatörde çalışır ancak cihazda kilitlenebilirdi. Boyutu 8 bitten küçük bir değer döndüren bir seçiciyi çağırmak için işlevini bildirin 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
);

Bu yöntemi çağırmak için aşağıdaki gibi bir kod kullanın:

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
    );

Seçici çağırma

Bir seçiciyi çağırmanın üç adımı vardır:

  1. Seçici hedefini alın.
  2. Seçici adını alın.
  3. Uygun bağımsız değişkenlerle çağrısı objc_msgSend yapın.

Seçici hedefleri

Seçici hedefi bir nesne örneği veya Objective-C sınıftır. Hedef bir örnekse ve ilişkili bir Xamarin.iOS türünden geldiyse özelliğini kullanın ObjCRuntime.INativeObject.Handle .

Hedef bir sınıfsa, ObjCRuntime.Class sınıf örneğine başvuru almak için öğesini kullanın ve ardından özelliğini kullanın Class.Handle .

Seçici adları

Seçici adları Apple belgelerinde listelenmiştir. Örneğin, NSString ve seçicileri içerir sizeWithFont:sizeWithFont:forWidth:lineBreakMode: . Eklenmiş ve sondaki iki nokta üst üsteler seçici adının bir parçasıdır ve atlanamaz.

Seçici adını aldıktan sonra bunun için bir ObjCRuntime.Selector örnek oluşturabilirsiniz.

arama objc_msgSend

objc_msgSend bir nesneye ileti (seçici) gönderir. Bu işlev ailesi en az iki gerekli bağımsız değişken alır: seçici hedefi (örnek veya sınıf tanıtıcısı), seçicinin kendisi ve seçici için gereken bağımsız değişkenler. Örnek ve seçici bağımsız değişkenleri olmalıdır System.IntPtrve kalan tüm bağımsız değişkenler seçicinin beklediği türle (örneğinnint, bir intiçin veya tüm NSObjecttüretilmiş türler için) System.IntPtr eşleşmelidir. kullanınNSObject.Handle bir tür örneği için bir IntPtr elde etmek için Objective-C özelliği.

Birden objc_msgSend fazla işlev vardır:

  • Yapı döndüren seçiciler için kullanın objc_msgSend_stret . ARM'de bu, numaralandırma olmayan tüm dönüş türlerini veya C yerleşik türlerinden herhangi birini (char, short, int, long, , float) doubleiçerir. x86'da (simülatör), bu yöntemin boyutu 8 bayttan büyük tüm yapılar için kullanılması gerekir (CGSize 8 bayttır ve simülatörde kullanılmaz objc_msgSend_stret ).
  • Yalnızca x86 üzerinde kayan nokta değeri döndüren seçiciler için kullanın objc_msgSend_fpret . Bu işlevin ARM'de kullanılması gerekmez; bunun yerine kullanın objc_msgSend.
  • Ana objc_msgSend işlevi diğer tüm seçiciler için kullanılır.

Hangi işlevleri çağırmanız gerektiğini belirledikten objc_msgSend sonra (simülatör ve cihazların her biri farklı bir yöntem gerektirebilir), işlevi daha sonra çağırmak üzere bildirmek için normal [DllImport] bir yöntem kullanabilirsiniz.

Önceden oluşturulmuş objc_msgSend bir bildirim kümesi içinde ObjCRuntime.Messagingbulunabilir.

Simülatörde ve cihazda farklı çağrılar

Yukarıda açıklandığı gibi, Objective-C üç tür objc_msgSend yöntem vardır: biri normal çağrılar için, biri kayan nokta değerleri döndüren çağrılar için (yalnızca x86) ve biri de yapı değerleri döndüren çağrılar için. İkincisi, içinde ObjCRuntime.Messagingson eki _stret içerir.

Belirli yapıları döndürecek bir yöntemi çağırırsanız (aşağıda açıklanan kurallar), dönüş değeriyle yöntemi ilk parametre olarak bir out değer olarak çağırmanız gerekir:

// The following returns a PointF structure:
PointF ret;
Messaging.PointF_objc_msgSend_stret_PointF_IntPtr (out ret, this.Handle, selConvertPointFromWindow.Handle, point, window.Handle);

Yöntemin ne zaman kullanılacağına ilişkin _stret_ kural x86 ve ARM'de farklılık gösterir. Bağlamalarınızın hem simülatörde hem de cihazda çalışmasını istiyorsanız, aşağıdaki gibi bir kod ekleyin:

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 yöntemini kullanma

ARM için oluştururken objc_msgSend_stretsabit listesi olmayan herhangi bir değer türü veya sabit listesi (int, , byte, short, long, doublefloat) için temel türlerden herhangi biri için.

x86 için oluştururken objc_msgSend_stretsabit listesi olmayan veya bir sabit listesi (int, , byte, short, long, doublefloat) için temel türlerden herhangi biri olmayan ve yerel boyutu 8 bayttan büyük olan herhangi bir değer türü için.

Kendi imzalarınızı oluşturma

Aşağıdaki gist, gerekirse kendi imzalarınızı oluşturmak için kullanılabilir.