Xamarin.iOS API Tasarımı
Mono'nun parçası olan temel Temel Sınıf Kitaplıklarına ek olarak Xamarin.iOS, geliştiricilerin Mono ile yerel iOS uygulamaları oluşturmasına olanak sağlamak için çeşitli iOS API'leri için bağlamalar içerir.
Xamarin.iOS'un merkezinde, C# dünyasını dünyayla Objective-C bir araya getiren ve CoreGraphics ve OpenGL ES gibi iOS C tabanlı API'ler için bağlamalar sağlayan bir birlikte çalışma altyapısı vardır.
Kodla Objective-C iletişim kurmak için alt düzey çalışma zamanı MonoTouch.ObjCRuntime içindedir. Ayrıca Foundation, CoreFoundation ve UIKit bağlamaları sağlanır.
Tasarım İlkeleri
Bu bölümde, Xamarin.iOS bağlamaları için bazı tasarım ilkelerimiz ayrıntılı olarak açıklanmıştır (bunlar macOS'ta için Mono bağlamaları olan Xamarin.Mac için Objective-C de geçerlidir):
Geliştiricilerin alt sınıf Objective-C sınıflarına izin ver:
- Mevcut bir sınıftan türetme
- Temel oluşturucuyu zincire çağırma
- Geçersiz kılma yöntemleri C# 'nin geçersiz kılma sistemi ile yapılmalıdır
- Alt sınıflama C# standart yapılarıyla çalışmalıdır
Geliştiricileri seçicilere Objective-C göstermeyin
Rastgele Objective-C kitaplıkları çağırmak için bir mekanizma sağlama
Ortak Objective-C görevleri kolay ve zor Objective-C görevleri mümkün hale getirme
Özellikleri C# özellikleri olarak kullanıma sunma Objective-C
Kesin türü belirlenmiş bir API'nin kullanıma sunma:
- Tür güvenliğini artırma
- Çalışma zamanı hatalarını en aza indirme
- Dönüş türlerinde IDE IntelliSense alma
- IDE açılır belgelerine izin verir
API'lerin IDE içinde keşfini teşvik edin:
Örneğin, aşağıdaki gibi zayıf türemiş bir diziyi ortaya çıkarmak yerine:
NSArray *getViews
Aşağıdaki gibi güçlü bir türü kullanıma sunar:
NSView [] Views { get; set; }
Güçlü türlerin kullanılması, Mac için Visual Studio API'ye göz atarken otomatik tamamlama gerçekleştirme olanağı sağlar, döndürülen değerde tüm
System.Array
işlemleri kullanılabilir hale getirir ve dönüş değerinin LINQ'a katılmasına izin verir.
Yerel C# türleri:
Sabit listeleri olması gereken ve
uint
parametrelerini öznitelikleri olan[Flags]
C# numaralandırmalarına ve C# numaralandırmalarına dönüştürmeint
Türü bağımsız
NSArray
nesneler yerine, dizileri kesin olarak yazılan diziler olarak kullanıma sunar.Olaylar ve bildirimler için kullanıcılara şu seçenekleri belirleyin:
- Varsayılan olarak kesin olarak yazılan bir sürüm
- Gelişmiş kullanım örnekleri için zayıf türemiş bir sürüm
Temsilci desenini destekleyin Objective-C :
- C# olay sistemi
- C# temsilcilerini (lambdalar, anonim yöntemler ve
System.Delegate
) API'ler için Objective-C blok olarak kullanıma sunma
Bütünleştirilmiş Kodlar
Xamarin.iOS, Xamarin.iOS Profilini oluşturan birçok derleme içerir. Derlemeler sayfasında daha fazla bilgi bulunur.
Ana Ad Alanları
ObjCRuntime
ObjCRuntime ad alanı, geliştiricilerin C# ile Objective-Carasında dünyalar arasında köprü oluşturmasına olanak tanır. Bu, Cocoa# ve Gtk# deneyimine göre iOS için özel olarak tasarlanmış yeni bir bağlamadır.
Vakıf
Foundation ad alanı, iOS'un parçası olan Foundation çerçevesiyle Objective-C birlikte çalışabilmek için tasarlanmış temel veri türlerini sağlar ve içindeki Objective-Cnesne odaklı programlama için temeldir.
Xamarin.iOS, C# dosyasındaki sınıf Objective-Chiyerarşisini yansıtır. Örneğin, Objective-C temel NSObject sınıfı Foundation.NSObject aracılığıyla C# ile kullanılabilir.
Foundation ad alanı temel alınan Objective-C Foundation türleri için bağlamalar sağlasa da, birkaç durumda temel alınan türleri .NET türlerine eşledik. Örneğin:
Çalışma zamanı, NSString ve NSArray ile ilgilenmek yerine bunları API'nin tamamında C# dizesis ve kesin olarak yazılan dizilerolarak kullanıma sunar.
Geliştiricilerin şu anda Xamarin.iOS'a bağlı olmayan üçüncü taraf Objective-C API'leri, diğer iOS API'lerini veya API'leri bağlamasına olanak sağlamak için burada çeşitli yardımcı API'ler kullanıma sunulur.
Bağlama API'leri hakkında daha fazla bilgi için Xamarin.iOS Bağlama Oluşturucu bölümüne bakın.
NSObject
NSObject türü tüm Objective-C bağlamaların temelini oluşturur. Xamarin.iOS türleri, iOS CocoaTouch API'lerinden iki tür sınıfını yansıtır: C türleri (genellikle CoreFoundation türleri olarak adlandırılır) ve Objective-C türler (tümü NSObject sınıfından türetilir).
Yönetilmeyen bir türü yansıtan her tür için, handle özelliği aracılığıyla yerel nesneyi elde etmek mümkündür.
Mono tüm nesneleriniz için çöp toplama sağlarken System.IDisposable Foundation.NSObject
arabirimini uygular. Çöp Toplayıcı'nın devreye geçmesini beklemek zorunda kalmadan herhangi bir NSObject'in kaynaklarını açıkça serbest bırakabilirsiniz. Kaynakları açıkça serbest bırakmak, büyük veri bloklarının işaretçilerini tutabilen UIImage'lar gibi ağır NSObjects kullanırken önemlidir.
Türünüzün belirlenimci sonlandırma gerçekleştirmesi gerekiyorsa NSObject.Dispose(bool) yöntemini geçersiz kılın Dispose parametresi "bool disposing" parametresidir ve true olarak ayarlanırsa dispose yönteminizin çağrılmakta olduğu anlamına gelir çünkü kullanıcı nesne üzerinde Dispose () adını açıkça çağırır. False değeri Dispose(bool disposing) yönteminizin sonlandırıcı iş parçacığındaki sonlandırıcıdan çağrıldığını gösterir.
Kategoriler
Xamarin.iOS 8.10'dan başlayarak C# dilinden kategoriler oluşturmak Objective-C mümkündür.
Bu işlem özniteliği kullanılarak yapılır ve özniteliğin Category
bağımsız değişkeni olarak genişletilen türü belirtir. Aşağıdaki örnekte örneğin NSString genişletilecektir.
[Category (typeof (NSString))]
Her kategori yöntemi, öznitelik kullanarak yöntemleri Objective-C dışarı aktarmak için normal mekanizmayı Export
kullanır:
[Export ("today")]
public static string Today ()
{
return "Today";
}
Tüm yönetilen uzantı yöntemleri statik olmalıdır, ancak C# dilinde uzantı yöntemleri için standart söz dizimini kullanarak örnek yöntemleri oluşturmak Objective-C mümkündür:
[Export ("toUpper")]
public static string ToUpper (this NSString self)
{
return self.ToString ().ToUpper ();
}
ve uzantı yönteminin ilk bağımsız değişkeni, yöntemin çağrıldığı örnek olacaktır.
Tam örnek:
[Category (typeof (NSString))]
public static class MyStringCategory
{
[Export ("toUpper")]
static string ToUpper (this NSString self)
{
return self.ToString ().ToUpper ();
}
}
Bu örnek, NSString sınıfına yerel bir toUpper örneği yöntemi ekler ve bu yöntem öğesinden Objective-Cçağrılabilir.
[Category (typeof (UIViewController))]
public static class MyViewControllerCategory
{
[Export ("shouldAutoRotate")]
static bool GlobalRotate ()
{
return true;
}
}
Bunun yararlı olduğu bir senaryo, kod tabanınızdaki tüm sınıf kümesine yöntem eklemektir; örneğin, bu durum tüm UIViewController
örneklerin döndürebileceklerini bildirmesine neden olur:
[Category (typeof (UINavigationController))]
class Rotation_IOS6 {
[Export ("shouldAutorotate:")]
static bool ShouldAutoRotate (this UINavigationController self)
{
return true;
}
}
PreserveAttribute
PreserveAttribute, uygulamanın boyutunu küçültmek için işlendiği aşamada bir türü veya türün bir üyesini korumak için mtouch'ı (Xamarin.iOS dağıtım aracı) bildirmek için kullanılan özel bir özniteliktir.
Uygulama tarafından statik olarak bağlı olmayan her üye kaldırılabilir. Bu nedenle, bu öznitelik statik olarak başvurulmayan, ancak uygulamanız tarafından hala gerekli olan üyeleri işaretlemek için kullanılır.
Örneğin, türleri dinamik olarak başlatırsanız, türlerinizin varsayılan oluşturucusunun korunmasını isteyebilirsiniz. XML serileştirmesi kullanıyorsanız, türlerinizin özelliklerini korumak isteyebilirsiniz.
Bu özniteliği bir türün her üyesine veya türün kendisine uygulayabilirsiniz. Türün tamamını korumak istiyorsanız, tür üzerinde [Koru (AllMembers = true)] söz dizimini kullanabilirsiniz.
UIKit
UIKit ad alanı, C# sınıfları biçiminde CocoaTouch'ı oluşturan tüm kullanıcı arabirimi bileşenlerine bire bir eşleme içerir. API, C# dilinde kullanılan kuralları izleyecek şekilde değiştirildi.
Yaygın işlemler için C# temsilcileri sağlanır. Daha fazla bilgi için temsilciler bölümüne bakın.
OpenGLES
OpenGLES için, OpenTK API'sinin değiştirilmiş bir sürümünü, CoreGraphics veri türlerini ve yapılarını kullanacak şekilde değiştirilmiş ve yalnızca iOS'ta kullanılabilen işlevselliği ortaya çıkararak OpenGL'ye nesne odaklı bir bağlama dağıtıyoruz.
OpenGLES 1.1 işlevselliği ES11.GL türü aracılığıyla kullanılabilir.
OpenGLES 2.0 işlevselliği ES20.GL türü aracılığıyla kullanılabilir.
OpenGLES 3.0 işlevselliği ES30.GL türü aracılığıyla kullanılabilir.
Bağlama Tasarımı
Xamarin.iOS yalnızca temel platform Objective-C için bir bağlama değildir. .NET tür sistemini genişletir ve C# ve Objective-C'yi daha iyi karıştırmak için sistemi sevk eder.
P/Invoke,Windows ve Linux'ta yerel kitaplıkları çağırmak için kullanışlı bir araç olduğu gibi veya Windows'ta COM birlikte çalışma için IJW desteği kullanılabildiği için Xamarin.iOS çalışma zamanını C# nesnelerini nesnelere bağlamayı Objective-C destekleyecek şekilde genişletir.
Sonraki birkaç bölümdeki tartışma, Xamarin.iOS uygulamaları oluşturan kullanıcılar için gerekli değildir, ancak geliştiricilerin işlerin nasıl yapıldığını anlamasına yardımcı olur ve daha karmaşık uygulamalar oluştururken onlara yardımcı olur.
Türler
Mantıklı olduğu durumlarda, C# türleri, C# evreninde alt düzey Temel türleri yerine kullanıma sunulur. Bu, API'nin NSString yerine C# "string" türünü kullandığı ve NSArray'yi açığa çıkarmak yerine kesin olarak yazılan C# dizilerini kullandığı anlamına gelir.
Genel olarak, Xamarin.iOS ve Xamarin.Mac tasarımında, temel alınan NSArray
nesne kullanıma sunulmaz. Bunun yerine çalışma zamanı, s'leri NSArray
otomatik olarak bazı NSObject
sınıfın kesin olarak yazılan dizilerine dönüştürür. Bu nedenle Xamarin.iOS, NSArray döndürmek için GetViews gibi zayıf türde bir yöntemi kullanıma sunmaz:
NSArray GetViews ();
Bunun yerine bağlama, aşağıdaki gibi kesin olarak belirlenmiş bir dönüş değeri sunar:
UIView [] GetViews ();
doğrudan kullanmak NSArray
isteyebileceğiniz ancak API bağlamasında NSArray
kullanımı önerilmez köşe durumları için içinde kullanıma sunulan yöntemlerden birkaçı vardır.
Ayrıca, CoreGraphics API'sinden , ve CGSize
değerlerini ortaya çıkarmak CGRect
yerine Klasik API'de, geliştiricilerin System.Drawing
OpenTK kullanan mevcut OpenGL kodunu korumalarına RectangleF
yardımcı olacak şekilde bunları , PointF
ve SizeF
uygulamalarıyla değiştirdikCGPoint
. Yeni 64 bit Birleşik API kullanılırken CoreGraphics API kullanılmalıdır.
Devralma
Xamarin.iOS API tasarımı, Objective-C geliştiricilerin türetilmiş bir sınıfta "override" anahtar sözcüğünü kullanarak ve "base" C# anahtar sözcüğünü kullanarak temel uygulamaya zincirleme yaparak yerel türleri C# türünü genişletecekleri şekilde genişletmesine olanak tanır.
Bu tasarım, geliştiricilerin geliştirme sürecinin bir parçası olarak seçicilerle Objective-C uğraşmaktan kaçınmasını sağlar çünkü sistemin tamamı Objective-C zaten Xamarin.iOS kitaplıklarında sarmalanmıştır.
Türler ve Arabirim Oluşturucusu
Arabirim Oluşturucusu tarafından oluşturulan türlerin örnekleri olan .NET sınıfları oluşturduğunuzda, tek IntPtr
bir parametre alan bir oluşturucu sağlamanız gerekir.
Yönetilen nesne örneğini yönetilmeyen nesneyle bağlamak için bu gereklidir.
Kod aşağıdaki gibi tek bir satırdan oluşur:
public partial class void MyView : UIView {
// This is the constructor that you need to add.
public MyView (IntPtr handle) : base (handle) {}
}
Temsilciler
Objective-C ve C# her dilde temsilci sözcüğü için farklı anlamlara sahiptir.
Objective-C Dünyada ve CocoaTouch hakkında çevrimiçi olarak bulabileceğiniz belgelerde temsilci, genellikle bir dizi yönteme yanıt verecek bir sınıfın örneğidir. Bu, C# arabirimine benzer ve farkı yöntemlerin her zaman zorunlu olmamasıdır.
Bu temsilciler UIKit ve diğer CocoaTouch API'lerinde önemli bir rol oynar. Bunlar çeşitli görevleri gerçekleştirmek için kullanılır:
- Kodunuz için bildirim sağlamak için (C# veya Gtk+'da olay teslimine benzer).
- Veri görselleştirme denetimlerine yönelik modelleri uygulamak için.
- Bir denetimin davranışını yönlendirmek için.
Programlama düzeni, bir denetimin davranışını değiştirmek üzere türetilmiş sınıfların oluşturulmasını en aza indirmek üzere tasarlanmıştır. Bu çözüm, ruhen diğer GUI araç setlerinin yıllar içinde yaptıklarına benzer: Gtk'in sinyalleri, Qt yuvaları, Winforms olayları, WPF/Silverlight olayları vb. Yüzlerce arabirime (her eylem için bir arabirim) sahip olmaktan kaçınmak veya geliştiricilerin ihtiyaç duymadığı çok fazla yöntem uygulamasına gerek duymamak için isteğe Objective-C bağlı yöntem tanımlarını destekler. Bu, tüm yöntemlerin uygulanmasını gerektiren C# arabirimlerinden farklıdır.
Sınıflarda Objective-C , bu programlama desenini kullanan sınıfların, arabirimin zorunlu bölümlerini ve isteğe bağlı bölümlerin sıfırını veya daha fazlasını uygulamak için gerekli olan adlı delegate
bir özelliği ortaya çıkardığını göreceksiniz.
Xamarin.iOS'ta bu temsilcilere bağlanmak için birbirini dışlayan üç mekanizma sunulur:
- Olaylar aracılığıyla.
- Bir özellik aracılığıyla
Delegate
kesin olarak yazıldı - Bir özellik aracılığıyla gevşek bir
WeakDelegate
şekilde yazıldı
Örneğin, UIWebView sınıfını göz önünde bulundurun. Bu, temsilci özelliğine atanan bir UIWebViewDelegate örneğine gönderilir.
Olaylar aracılığıyla
Birçok tür için, Xamarin.iOS otomatik olarak uygun bir temsilci oluşturur ve bu temsilci çağrıları UIWebViewDelegate
C# olaylarına iletir. UIWebView
için:
- webViewDidStartLoad yöntemi UIWebView.LoadStarted olayıyla eşlenir .
- webViewDidFinishLoad yöntemi UIWebView.LoadFinished olayıyla eşlenir .
- webView:didFailLoadWithError yöntemi UIWebView.LoadError olayına eşlenir.
Örneğin, bu basit program bir web görünümü yüklenirken başlangıç ve bitiş saatlerini kaydeder:
DateTime startTime, endTime;
var web = new UIWebView (new CGRect (0, 0, 200, 200));
web.LoadStarted += (o, e) => startTime = DateTime.Now;
web.LoadFinished += (o, e) => endTime = DateTime.Now;
Özellikler aracılığıyla
Olaylar, olaya birden fazla abone olduğunda yararlıdır. Ayrıca, olaylar koddan dönüş değeri olmayan durumlara sınırlıdır.
Kodun bir değer döndürmesi beklenen durumlarda, özellikler yerine bunu seçtik. Bu, bir nesnede belirli bir zamanda yalnızca bir yöntemin ayarlanabileceği anlamına gelir.
Örneğin, bir için işleyicide ekrandaki klavyeyi kapatmak için UITextField
bu mekanizmayı kullanabilirsiniz:
void SetupTextField (UITextField tf)
{
tf.ShouldReturn = delegate (textfield) {
textfield.ResignFirstResponder ();
return true;
}
}
UITextField
Bu durumda 's ShouldReturn
özelliği, bir bool değeri döndüren bir temsilci olarak bağımsız değişken olarak alır ve TextField'ın Return düğmesine basıldığında bir şey yapıp yapmayacağını belirler. Yöntemimizde çağırana true değerini döndüreceğiz, ancak klavyeyi de ekrandan kaldırıyoruz (metin alanı çağırdığında ResignFirstResponder
bu durum gerçekleşir).
Temsilci Özelliği Aracılığıyla Kesin Olarak Yazıldı
Olayları kullanmamak isterseniz kendi UIWebViewDelegate alt sınıfınızı sağlayabilir ve UIWebView.Delegate özelliğine atayabilirsiniz. UIWebView.Delegate atandıktan sonra, UIWebView olay dağıtma mekanizması artık çalışmaz ve ilgili olaylar gerçekleştiğinde UIWebViewDelegate yöntemleri çağrılır.
Örneğin, bu basit tür bir web görünümünü yüklemek için gereken süreyi kaydeder:
class Notifier : UIWebViewDelegate {
DateTime startTime, endTime;
public override LoadStarted (UIWebView webview)
{
startTime = DateTime.Now;
}
public override LoadingFinished (UIWebView webView)
{
endTime= DateTime.Now;
}
}
Yukarıdakiler aşağıdaki gibi kodlarda kullanılır:
var web = new UIWebView (new CGRect (0, 0, 200, 200));
web.Delegate = new Notifier ();
Yukarıdakiler bir UIWebViewer oluşturur ve iletiye yanıt vermek için oluşturduğumuz bir sınıf olan Notifier örneğine ileti göndermesini bildirir.
Bu desen, örneğin UIWebView örneğinde olduğu gibi belirli denetimlerin davranışını denetlemek için de kullanılır. UIWebView.ShouldStartLoad özelliği, örneğin sayfanın yüklenip yüklenmeyeceğini denetlemesine UIWebView
olanak tanırUIWebView
.
Desen, birkaç denetim için isteğe bağlı verileri sağlamak için de kullanılır. Örneğin, UITableView denetimi güçlü bir tablo işleme denetimidir ve hem görünüm hem de içerik uiTableViewDataSource örneği tarafından yönlendirilir
WeakDelegate Özelliği Aracılığıyla Gevşek Bir Şekilde Yazıldı
Kesin olarak türü belirlenmiş özelliğine ek olarak, geliştiricinin isterse nesneleri farklı bağlamasına olanak tanıyan zayıf bir türe sahip temsilci de vardır.
Xamarin.iOS'un bağlamasında kesin olarak belirlenmiş Delegate
bir özelliğin kullanıma sunulduğu her yerde, buna karşılık gelen WeakDelegate
bir özellik de kullanıma sunulur.
kullanırken, seçiciyi WeakDelegate
belirtmek için Export özniteliğini kullanarak sınıfınızı düzgün bir şekilde dekore etmek sizin sorumluluğunuzdadır. Örneğin:
class Notifier : NSObject {
DateTime startTime, endTime;
[Export ("webViewDidStartLoad:")]
public void LoadStarted (UIWebView webview)
{
startTime = DateTime.Now;
}
[Export ("webViewDidFinishLoad:")]
public void LoadingFinished (UIWebView webView)
{
endTime= DateTime.Now;
}
}
[...]
var web = new UIWebView (new CGRect (0, 0, 200, 200));
web.WeakDelegate = new Notifier ();
WeakDelegate
Özellik atandıktan sonra özellik Delegate
kullanılmaz. Ayrıca, yöntemini [Dışarı Aktar] istediğiniz devralınan bir temel sınıfta uygularsanız, bunu genel bir yöntem yapmanız gerekir.
Temsilci deseninin Objective-C C ile eşleştirilmesi#
Şuna benzer örnekler gördüğünüzde Objective-C :
foo.delegate = [[SomethingDelegate] alloc] init]
Bu, dile "SomethingDelegate" sınıfının bir örneğini oluşturup oluşturmasını ve foo değişkenindeki temsilci özelliğine değer atamasını bildirir. Bu mekanizma Xamarin.iOS tarafından desteklenir ve C# söz dizimi şöyledir:
foo.Delegate = new SomethingDelegate ();
Xamarin.iOS'ta, temsilci sınıflarına Objective-C eşlenen kesin olarak belirlenmiş sınıflar sağladık. Bunları kullanmak için Xamarin.iOS uygulaması tarafından tanımlanan yöntemleri alt sınıfa alıp geçersiz kılacaksınız. Nasıl çalıştıkları hakkında daha fazla bilgi için aşağıdaki "Modeller" bölümüne bakın.
Temsilcileri C ile Eşleme#
UIKit genel olarak temsilcileri iki biçimde kullanır Objective-C .
İlk form, bir bileşenin modeli için bir arabirim sağlar. Örneğin, liste görünümü için veri depolama tesisi gibi bir görünüm için isteğe bağlı veri sağlamaya yönelik bir mekanizma olarak. Böyle durumlarda, her zaman uygun sınıfın bir örneğini oluşturmanız ve değişkenini atamanız gerekir.
Aşağıdaki örnekte, dizeleri kullanan bir model için uygulamasını sağlıyoruz UIPickerView
:
public class SampleTitleModel : UIPickerViewTitleModel {
public override string TitleForRow (UIPickerView picker, nint row, nint component)
{
return String.Format ("At {0} {1}", row, component);
}
}
[...]
pickerView.Model = new MyPickerModel ();
İkinci form, olaylar için bildirim sağlamaktır. Bu gibi durumlarda, API'yi yukarıda özetlenen biçimde kullanıma sunmaya devam etsek de, hızlı işlemler için kullanılması daha kolay ve C# dilinde anonim temsilciler ve lambda ifadeleriyle tümleştirilmiş C# olayları da sağlarız.
Örneğin, olaylara UIAccelerometer
abone olabilirsiniz:
UIAccelerometer.SharedAccelerometer.Acceleration += (sender, args) => {
UIAcceleration acc = args.Acceleration;
Console.WriteLine ("Time={0} at {1},{2},{3}", acc.Time, acc.X, acc.Y, acc.Z);
}
İki seçenek mantıklı oldukları durumlarda kullanılabilir, ancak programcı olarak birini veya diğerini seçmeniz gerekir. Kesin olarak türü belirlenmiş bir yanıtlayıcı/temsilcinin kendi örneğini oluşturur ve atarsanız, C# olayları işlevsel olmaz. C# olaylarını kullanırsanız, yanıtlayıcı/temsilci sınıfınızdaki yöntemler hiçbir zaman çağrılmaz.
Kullanılan UIWebView
önceki örnek aşağıdaki gibi C# 3.0 lambda'lar kullanılarak yazılabilir:
var web = new UIWebView (new CGRect (0, 0, 200, 200));
web.LoadStarted += () => { startTime = DateTime.Now; }
web.LoadFinished += () => { endTime = DateTime.Now; }
Olaylara Yanıt Verme
Kodda Objective-C , bazen birden çok denetim için olay işleyicileri ve birden çok denetim için bilgi sağlayıcısı, aynı sınıfta barındırılır. Bu mümkündür çünkü sınıflar iletilere yanıt verir ve sınıflar iletilere yanıt verdiği sürece nesneleri birbirine bağlamak mümkündür.
Daha önce de açıklandığı gibi, Xamarin.iOS hem C# olay tabanlı programlama modelini hem Objective-C de temsilci desenini destekler. Burada temsilciyi uygulayan ve istenen yöntemleri geçersiz kılan yeni bir sınıf oluşturabilirsiniz.
Birden çok farklı işlem için yanıtlayanların tümünün bir sınıfın aynı örneğinde barındırıldığı 'nin desenini desteklemek de mümkündür Objective-C. Ancak bunu yapmak için Xamarin.iOS bağlamasının düşük düzey özelliklerini kullanmanız gerekir.
Örneğin, sınıfınızın bir sınıfın UITextFieldDelegate.textFieldShouldClear
aynı örneğinde hem : iletisine hem UIWebViewDelegate.webViewDidStartLoad
de öğesine yanıt vermesini istiyorsanız , [Export] öznitelik bildirimini kullanmanız gerekir:
public class MyCallbacks : NSObject {
[Export ("textFieldShouldClear:"]
public bool should_we_clear (UITextField tf)
{
return true;
}
[Export ("webViewDidStartLoad:")]
public void OnWebViewStart (UIWebView view)
{
Console.WriteLine ("Loading started");
}
}
Yöntemlerin C# adları önemli değildir; önemli olan tek şey [Export] özniteliğine geçirilen dizelerdir.
Bu programlama stilini kullanırken, C# parametrelerinin çalışma zamanı altyapısının geçireceği gerçek türlerle eşleştiğinden emin olun.
Modeller
UIKit depolama tesislerinde veya yardımcı sınıflar kullanılarak uygulanan yanıtlayıcılarda bunlar kodda Objective-C temsilci olarak başvurulur ve protokol olarak uygulanır.
Objective-C protokoller arabirim gibidir, ancak isteğe bağlı yöntemleri destekler; yani protokolün çalışması için tüm yöntemlerin uygulanması gerekmez.
Modeli uygulamanın iki yolu vardır. El ile uygulayabilir veya var olan kesin olarak belirlenmiş tanımları kullanabilirsiniz.
Xamarin.iOS ile bağlı olmayan bir sınıf uygulamaya çalıştığınızda el ile mekanizma gereklidir. Bunu yapmak kolaydır:
- Sınıfınıza çalışma zamanıyla kayıt için bayrak ekleyin
- Geçersiz kılmak istediğiniz her yönteme gerçek seçici adıyla [Export] özniteliğini uygulayın
- Sınıfın örneğini oluşturup geçirin.
Örneğin, aşağıdakiler UIApplicationDelegate protokol tanımında isteğe bağlı yöntemlerden yalnızca birini uygular:
public class MyAppController : NSObject {
[Export ("applicationDidFinishLaunching:")]
public void FinishedLaunching (UIApplication app)
{
SetupWindow ();
}
}
Seçici Objective-C adı ("applicationDidFinishLaunching:") Export özniteliğiyle bildirilir ve sınıf özniteliğine [Register]
kaydedilir.
Xamarin.iOS, el ile bağlama gerektirmeyen, kullanıma hazır, kesin olarak belirlenmiş bildirimler sağlar. Xamarin.iOS çalışma zamanı, bu programlama modelini desteklemek için sınıf bildiriminde [Model] özniteliğini destekler. Bu, çalışma zamanına, yöntemler açıkça uygulanmadığı sürece sınıfındaki tüm yöntemlerin kablolarını oluşturmaması gerektiğini bildirir.
Bu, UIKit'te isteğe bağlı yöntemlerle bir protokolü temsil eden sınıfların şöyle yazıldığını gösterir:
[Model]
public class SomeViewModel : NSObject {
[Export ("someMethod:")]
public virtual int SomeMethod (TheView view) {
throw new ModelNotImplementedException ();
}
...
}
Yöntemlerden yalnızca bazılarını uygulayan bir model uygulamak istediğinizde tek yapmanız gereken ilgilendiğiniz yöntemleri geçersiz kılmak ve diğer yöntemleri yoksaymaktır. Çalışma zamanı yalnızca üzerine yazılan yöntemleri bağlar, dünyaya özgün yöntemleri Objective-C bağlamaz.
Önceki el ile örneğin eşdeğeri:
public class AppController : UIApplicationDelegate {
public override void FinishedLaunching (UIApplication uia)
{
...
}
}
Bunun avantajları, seçiciyi, bağımsız değişkenlerin türlerini veya C# ile eşlemeyi bulmak için üst bilgi dosyalarını incelemenize gerek Objective-C olmaması ve güçlü türlerin yanı sıra Mac için Visual Studio'dan intellisense almanızdır
XIB Prizleri ve C#
Bu, Outlet'lerin C# ile nasıl tümleştirildiğinden ve Xamarin.iOS'un ileri düzey kullanıcılarına sağlandığına ilişkin alt düzey bir açıklamadır. Mac için Visual Studio kullanırken eşleme, sizin için uçuşta oluşturulan kod kullanılarak otomatik olarak arka planda gerçekleştirilir.
Kullanıcı arabiriminizi Interface Builder ile tasarlarken, yalnızca uygulamanın görünümünü tasarlarsınız ve bazı varsayılan bağlantılar kurarsınız. Program aracılığıyla bilgi getirmek, çalışma zamanında denetimin davranışını değiştirmek veya çalışma zamanında denetimi değiştirmek istiyorsanız, denetimlerden bazılarını yönetilen kodunuzla bağlamak gerekir.
Bu işlem birkaç adımda gerçekleştirilir:
- Çıkış bildirimini Dosyanızın sahibine ekleyin.
- Bağlan Denetiminizi Dosyanın sahibi.
- Kullanıcı arabirimini ve bağlantıları XIB/NIB dosyanızda depolayın.
- ÇALıŞMA zamanında NIB dosyasını yükleyin.
- Çıkış değişkenine erişin.
(1) ile (3) arasında adımlar, Apple'ın Interface Builder ile arabirim oluşturma belgelerinde ele alınmıştır.
Xamarin.iOS kullanırken uygulamanızın UIViewController'dan türetilen bir sınıf oluşturması gerekir. Şu şekilde uygulanır:
public class MyViewController : UIViewController {
public MyViewController (string nibName, NSBundle bundle) : base (nibName, bundle)
{
// You can have as many arguments as you want, but you need to call
// the base constructor with the provided nibName and bundle.
}
}
Ardından ViewController'ınızı bir NIB dosyasından yüklemek için şunları yaparsınız:
var controller = new MyViewController ("HelloWorld", NSBundle.MainBundle, this);
Bu, NIB'den kullanıcı arabirimini yükler. Şimdi, çıkışlara erişmek için çalışma zamanına erişmek istediğimizi bildirmek gerekir. Bunu yapmak için alt sınıfın UIViewController
özellikleri bildirmesi ve bunlara [Bağlan] özniteliğiyle ek açıklama eklemesi gerekir. Böyle:
[Connect]
UITextField UserName {
get {
return (UITextField) GetNativeField ("UserName");
}
set {
SetNativeField ("UserName", value);
}
}
Özellik uygulaması, gerçek yerel türün değerini getiren ve depolayan uygulamadır.
Mac için Visual Studio ve InterfaceBuilder kullanırken bu konuda endişelenmeniz gerekmez. Mac için Visual Studio, bildirilen tüm çıkışları projenizin bir parçası olarak derlenmiş kısmi bir sınıftaki kodla otomatik olarak yansıtır.
Seçiciler
Programlamanın temel kavramlarından biri Objective-C seçicidir. Genellikle bir seçici geçirmenizi gerektiren veya kodunuzun bir seçiciye yanıt vermesini bekleyen API'lerle karşılaşırsınız.
C# dilinde yeni seçiciler oluşturmak kolaydır; yalnızca sınıfın ObjCRuntime.Selector
yeni bir örneğini oluşturur ve sonucu API'de gerekli olan herhangi bir yerde kullanırsınız. Örneğin:
var selector_add = new Selector ("add:plus:");
C# yöntemi bir seçici çağrısına yanıt vermek için türünden NSObject
devralınmalıdır ve C# yöntemi özniteliği kullanılarak [Export]
seçici adıyla dekore edilmelidir. Örneğin:
public class MyMath : NSObject {
[Export ("add:plus:")]
int Add (int first, int second)
{
return first + second;
}
}
Varsa, seçici adları tüm ara ve sondaki iki nokta üst üste (":") dahil olmak üzere tam olarak eşleşmelidir .
NSObject Oluşturucuları
Xamarin.iOS'ta türetilen NSObject
çoğu sınıf, nesnenin işlevselliğine özgü oluşturucuları kullanıma sunar, ancak hemen belirgin olmayan çeşitli oluşturucuları da kullanıma sunar.
Oluşturucular aşağıdaki gibi kullanılır:
public Foo (IntPtr handle)
Bu oluşturucu, çalışma zamanının sınıfınızı yönetilmeyen bir sınıfla eşlemesi gerektiğinde sınıfınızın örneğini oluşturmak için kullanılır. Bir XIB/NIB dosyası yüklediğinizde bu durum ortaya çıkar. Bu noktada, Objective-C çalışma zamanı yönetilmeyen dünyada bir nesne oluşturmuş olacak ve yönetilen tarafı başlatmak için bu oluşturucu çağrılacaktır.
Genellikle tek yapmanız gereken handle parametresiyle temel oluşturucuyu çağırmak ve gövdede gerekli başlatmaları yapmaktır.
public Foo ()
Bu, bir sınıfın varsayılan oluşturucusdur ve Xamarin.iOS tarafından sağlanan sınıflarda Foundation.NSObject sınıfını ve aralarındaki tüm sınıfları başlatır ve sonunda bunu sınıfındaki yöntemine Objective-Cinit
zincirler.
public Foo (NSObjectFlag x)
Bu oluşturucu örneği başlatmak için kullanılır, ancak kodun sonunda "init" yöntemini çağırmasını Objective-C önler. Bunu genellikle başlatma için önceden kaydolmuş olduğunuzda (oluşturucunuzda kullandığınızda [Export]
) veya başka bir ortalama aracılığıyla başlatma işleminizi zaten gerçekleştirdiğinizde kullanırsınız.
public Foo (NSCoder coder)
Bu oluşturucu, nesnenin bir NSCoding örneğinden başlatıldığı durumlar için sağlanır.
Özel durumlar
Xamarin.iOS API tasarımı, C# özel durumları olarak özel durumlar oluşturmaz Objective-C . Tasarım, ilk etapta dünyaya çöp gönderilmez Objective-C ve geçersiz veriler dünyaya geçirilmeden Objective-C önce, üretilmesi gereken tüm özel durumlar bağlama tarafından oluşturulur.
Notifications
Hem iOS hem de OS X'te geliştiriciler, temel alınan platform tarafından yayınlanan bildirimlere abone olabilir. Bu yöntem kullanılarak NSNotificationCenter.DefaultCenter.AddObserver
yapılır. AddObserver
yöntemi iki parametre alır; biri abone olmak istediğiniz bildirimdir; diğeri bildirim yükseltildiğinde çağrılacak yöntemdir.
Hem Xamarin.iOS hem de Xamarin.Mac'te, çeşitli bildirimlerin anahtarları bildirimleri tetikleyen sınıfta barındırılır. Örneğin, tarafından UIMenuController
tetiklenen bildirimler sınıflarda UIMenuController
"Notification" adıyla biten özellikler olarak static NSString
barındırılır.
Bellek Yönetimi
Xamarin.iOS'un artık kullanımda olmayan kaynakları sizin için serbest bırakma işlemini üstlenecek bir çöp toplayıcısı vardır. Atık toplayıcıya ek olarak, türetilen NSObject
tüm nesneler arabirimini System.IDisposable
uygular.
NSObject ve IDisposable
Arabirimin IDisposable
kullanıma açılması, geliştiricilerin büyük bellek bloklarını kapsülleyebilecek nesneleri (örneğin, UIImage
masum bir işaretçi gibi görünse de 2 megabaytlık bir görüntüye işaret ediyor olabilir) ve diğer önemli ve sonlu kaynakları (video kod çözme arabelleği gibi) serbest bırakmalarına yardımcı olmak için kullanışlı bir yoldur.
NSObject, IDisposable arabirimini ve ayrıca .NET Dispose desenini uygular. Bu, NSObject alt sınıfı olan geliştiricilerin Dispose davranışını geçersiz kılmasına ve isteğe bağlı olarak kendi kaynaklarını serbest bırakmasına olanak tanır. Örneğin, bir dizi görüntünün etrafında duran bu görünüm denetleyicisini göz önünde bulundurun:
class MenuViewController : UIViewController {
UIImage breakfast, lunch, dinner;
[...]
public override void Dispose (bool disposing)
{
if (disposing){
if (breakfast != null) breakfast.Dispose (); breakfast = null;
if (lunch != null) lunch.Dispose (); lunch = null;
if (dinner != null) dinner.Dispose (); dinner = null;
}
base.Dispose (disposing)
}
}
Yönetilen bir nesne atıldığında, artık yararlı olmaz. Yine de nesnelere bir başvurunuz olabilir, ancak nesne bu noktada tüm amaçlar ve amaçlar için geçersizdir. Atılan bir nesnedeki herhangi bir yönteme erişmeye çalışırsanız, bazı .NET API'leri objectDisposedException oluşturarak bunu güvence altına alır, örneğin:
var image = UIImage.FromFile ("demo.png");
image.Dispose ();
image.XXX = false; // this at this point is an invalid operation
"image" değişkenine yine de erişebilseniz bile, bu gerçekten geçersiz bir başvurudur ve artık görüntüyü tutan nesneye Objective-C işaret etmez.
Ancak C# dilinde bir nesnenin yok edilmesi, nesnenin mutlaka yok edilmesi anlamına gelmez. Tek yapmanız gereken C# öğesinin nesneye yaptığı başvuruyu serbest bırakmaktır. Cocoa ortamının kendi kullanımı için bir başvuru saklamış olması mümkündür. Örneğin, UIImageView'ın Image özelliğini bir görüntüye ayarlar ve ardından görüntüyü atarsanız, temel alınan UIImageView kendi başvurusunu almış ve kullanımı bitene kadar bu nesneye başvuruyu tutacaktır.
Dispose ne zaman çağrılır?
Nesnenizden kurtulmak için Mono'ya ihtiyacınız olduğunda Dispose çağrısı yapın. Olası bir kullanım örneği, Mono'nun NSObject'inizin bellek veya bilgi havuzu gibi önemli bir kaynağa başvuruda bulunduğu hakkında bilgi sahibi olmamasıdır. Bu gibi durumlarda, Mono'nun çöp toplama döngüsü gerçekleştirmesini beklemek yerine hemen belleğe başvuruyu serbest bırakmak için Dispose çağrısı yapmanız gerekir.
Mono, C# dizelerinden NSString başvuruları oluşturduğunda, atık toplayıcının yapması gereken iş miktarını azaltmak için bunları hemen atacaktır. Ne kadar az nesneyle başa çıkılırsa GC o kadar hızlı çalışır.
Nesnelere Başvurular Ne Zaman Tutulacak?
Otomatik bellek yönetiminin sahip olduğu bir yan etki, GC'nin kullanılmayan nesnelere başvuru olmadığı sürece bu nesnelerden kurtulmasıdır. Bu, bazen şaşırtıcı yan etkilere neden olabilir. Örneğin, en üst düzey görünüm denetleyicinizi veya en üst düzey pencerenizi tutmak için yerel bir değişken oluşturursanız ve bunların arkanızda kaybolmasına neden olursunuz.
Statik veya örnek değişkenlerinizde nesnelerinize yönelik bir başvuru tutmazsanız Mono, kendilerinde Dispose() yöntemini memnuniyetle çağırır ve nesneye başvuruyu serbest bırakır. Bekleyen tek başvuru bu olabileceğinden, Objective-C çalışma zamanı nesneyi sizin için yok eder.