Xamarin.iOS'ta Olaylar, Protokoller ve Temsilciler
Xamarin.iOS, çoğu kullanıcı etkileşimi için olayları ortaya çıkarmak için denetimleri kullanır. Xamarin.iOS uygulamaları bu olayları geleneksel .NET uygulamalarıyla çok aynı şekilde tüketir. Örneğin, Xamarin.iOS UIButton sınıfında TouchUpInside adlı bir olay vardır ve bu sınıf ve olay bir .NET uygulamasında olduğu gibi bu olayı tüketir.
Bu .NET yaklaşımının yanı sıra Xamarin.iOS, daha karmaşık etkileşim ve veri bağlama için kullanılmaktadır. Bu metodoloji, Apple'ın temsilciler ve protokoller olarak çağıran yöntemini kullanır. Temsilciler kavram olarak C# içinde temsilcilere benzer, ancak tek bir yöntem tanımlayarak çağırmak yerine, içinde bir temsilci bir protokole uygun tüm Objective-C bir sınıftır. Protokol, C# arabirimine benzer ancak yöntemleri isteğe bağlı olabilir. Örneğin, bir UITableView'u verilerle doldurmak için UITableView'ın kendisini doldurmak için çağırdığını UITableViewDataSource protokolünde tanımlanan yöntemleri uygulayan bir temsilci sınıfı oluşturabilirsiniz.
Bu makalede tüm bu konular hakkında bilgi edinmek ve Xamarin.iOS'ta geri çağırma senaryolarını işlemeye ilişkin sağlam bir temel sağlar, örneğin:
- Olaylar – UIKit denetimleriyle .NET olaylarını kullanma.
- Protokoller: Learning protokollerin ne olduğunu ve nasıl kullanıldıklarını gösterir ve harita ek açıklaması için veri sağlayan bir örnek oluşturulur.
- Temsilciler: Learning ek açıklama içeren kullanıcı etkileşimini işlemek için harita örneğini genişleterek, sonra güçlü ve zayıf temsilciler arasındaki farkı ve bunların her biri ne zaman kullanmayacaklarını öğrenerek temsilciler hakkında bilgi sağlar.
Protokolleri ve temsilcileri göstermek için, burada gösterildiği gibi bir haritaya ek açıklama ekleyen basit bir harita uygulaması oluştururuz:
Bu uygulamayla çalışmaya başlamadan önce UIKit altındaki .NET olaylarına bakalım.
UIKit ile .NET Olayları
Xamarin.iOS, UIKit denetimlerde .NET olaylarını gösterir. Örneğin UIButton' da C# lambda ifadesi kullanan aşağıdaki kodda gösterildiği gibi .NET'te normalde işlene bir TouchUpInside olayı vardır:
aButton.TouchUpInside += (o,s) => {
Console.WriteLine("button touched");
};
Bunu C# 2.0 stilinde anonim bir yöntemle de gerçekleştirebilirsiniz:
aButton.TouchUpInside += delegate {
Console.WriteLine ("button touched");
};
Yukarıdaki kod ViewDidLoad UIViewController'ın yönteminde kabloludur. değişkeni, aButton Xcode koduna veya kodla Interface Builder bir düğmeye başvurur.
Xamarin.iOS, kodunuzu denetimle oluşan bir etkileşime bağlamanın hedef eylem stilini de destekler.
iOS hedef eylemi deseni hakkında daha fazla ayrıntı için Apple'ın iOS Geliştirici Kitaplığı'Target-Action Temel Uygulama Yetkinlikleri'nin iOS için temel uygulama yetkinlikleri bölümüne bakın.
Daha fazla bilgi için bkz. Xcode ile kullanıcı arabirimleri tasarlama.
Ekinlikler
UIControl'dan gelen olaylara müdahale etmek için C# lambdaları ve temsilci işlevleri kullanmaktan alt düzey API'leri kullanmaya kadar çeşitli Objective-C seçenekleriniz vardır.
Aşağıdaki bölümde, ne kadar denetime ihtiyacınız olduğuna bağlı olarak touchDown olaylarını bir düğmede nasıl yakalayabilirsiniz?
C# Stili
Temsilci söz dizimlerini kullanma:
UIButton button = MakeTheButton ();
button.TouchDown += delegate {
Console.WriteLine ("Touched");
};
Bunun yerine lambdaları tercih ediyorsanız:
button.TouchDown += () => {
Console.WriteLine ("Touched");
};
Birden çok düğmeye sahip olmak için aynı işleyiciyi kullanarak aynı kodu paylaşın:
void handler (object sender, EventArgs args)
{
if (sender == button1)
Console.WriteLine ("button1");
else
Console.WriteLine ("some other button");
}
button1.TouchDown += handler;
button2.TouchDown += handler;
Birden fazla olay tür izleme
UIControlEvent bayrakları için C# olaylarının tek tek bayraklara bire bir eşlemesi vardır. Aynı kod parçasının iki veya daha fazla olay işlemesi için yöntemini UIControl.AddTarget kullanın:
button.AddTarget (handler, UIControlEvent.TouchDown | UIControlEvent.TouchCancel);
Lambda söz dizimlerini kullanma:
button.AddTarget ((sender, event)=> Console.WriteLine ("An event happened"), UIControlEvent.TouchDown | UIControlEvent.TouchCancel);
Belirli bir nesne örneğine bağlanarak ve belirli bir seçiciyi iptal etmek gibi alt düzey Objective-C özelliklerini kullanıyorsanız:
[Export ("MySelector")]
void MyObjectiveCHandler ()
{
Console.WriteLine ("Hello!");
}
// In some other place:
button.AddTarget (this, new Selector ("MySelector"), UIControlEvent.TouchDown);
Örnek yöntemini devralınan bir temel sınıfta uygulayan bir genel yöntem olması gerektiğini lütfen unutmayın.
Protokoller
Protokol, yöntem Objective-C bildirimlerinin listesini sağlayan bir dil özelliğidir. Temel fark, bir protokolün isteğe bağlı yöntemlere sahip olmasıdır ve C# arabirimine benzer bir amaca hizmet eder. Bir protokolü benimseyen sınıf bunları uygulamazsa, isteğe bağlı yöntemler çağrılır. Ayrıca, bir C# sınıfının birden çok arabirim uygulaya kadar içinde tek bir sınıf Objective-C birden çok protokol uygulayabilirsiniz.
Apple, iOS genelinde protokolleri kullanarak sınıfların benimseneceği anlaşmaları tanımlarken, uygulama sınıfını çağıranın dışında bırakarak aynı C# arabirimi gibi çalışıyor. Protokoller hem temsilci olmayan senaryolarda (örneğin, sonraki örnekte gösterildiği gibi) hem de temsilcilerle (bu belgenin ilerleyen kısımlarında, Temsilciler MKAnnotation bölümünde gösterildiği gibi) kullanılır.
Xamarin.ios ile Protokoller
Objective-CŞimdi Xamarin.iOS'tan bir protokol kullanarak bir örneği bakalım. Bu örnekte, çerçevenin MKAnnotation bir parçası olan protokolü kullan MapKit kullanıruz. MKAnnotation , onu benimseyen herhangi bir nesnenin haritaya eklen bir ek açıklama hakkında bilgi sağlamasını sağlayan bir protokoldür. Örneğin, uygulayan bir nesne MKAnnotation ek açıklamanın konumunu ve ilişkili başlığı sağlar.
Bu şekilde MKAnnotation protokol, ek açıklamaya eşlik etmek için ilgili verileri sağlamak için kullanılır. Ek açıklamanın kendisi için gerçek görünüm, protokolü benimseyen nesnedeki verilerden MKAnnotation yerleşiktir. Örneğin, kullanıcı ek açıklamaya (aşağıdaki ekran görüntüsünde gösterildiği gibi) dokunarak görünen açıklama çizgisinin metni, protokolü uygulayan sınıftaki Title özelliğinden gelir:
Sonraki bölümde açıklandığı gibi, ProtokollereDerinlemesine Bakın , Xamarin.iOS protokolleri soyut sınıflara bağlar. Protokol için, bağlı C# sınıfı protokolün adını taklit etmek için adlandırılmıştır ve CocoaTouch kök temel sınıfı olan sınıfının bir MKAnnotationMKAnnotation alt NSObject sınıfıdır. Protokol, koordinat için bir getter ve setter'ın uygulanmasını gerektirir; ancak başlık ve alt konu başlığı isteğe bağlıdır. Bu nedenle, MKAnnotation sınıfında özelliği CoordinateMKAnnotationve uygulanması gerekir ve ve özellikleri sanal olarak işaretlenir ve aşağıda gösterildiği gibi isteğe Title bağlı hale Subtitle geldi: Coordinate
[Register ("MKAnnotation"), Model ]
public abstract class MKAnnotation : NSObject
{
public abstract CLLocationCoordinate2D Coordinate
{
[Export ("coordinate")]
get;
[Export ("setCoordinate:")]
set;
}
public virtual string Title
{
[Export ("title")]
get
{
throw new ModelNotImplementedException ();
}
}
public virtual string Subtitle
{
[Export ("subtitle")]
get
{
throw new ModelNotImplementedException ();
}
}
...
}
Herhangi bir sınıf, özelliği uygulanmış olduğu sürece yalnızca 'den MKAnnotation türeterek ek açıklama Coordinate verileri sağlar. Örneğin, oluşturucuda koordinatı alan ve başlık için bir dize döndüren örnek bir sınıf aşağıdaki gibidir:
/// <summary>
/// Annotation class that subclasses MKAnnotation abstract class
/// MKAnnotation is bound by Xamarin.iOS to the MKAnnotation protocol
/// </summary>
public class SampleMapAnnotation : MKAnnotation
{
string title;
public SampleMapAnnotation (CLLocationCoordinate2D coordinate)
{
Coordinate = coordinate;
title = "Sample";
}
public override CLLocationCoordinate2D Coordinate { get; set; }
public override string Title {
get {
return title;
}
}
}
Bağlı olduğu protokol aracılığıyla, alt sınıfların oluşturduğu ek açıklama görünümünü oluşturduğunda harita tarafından kullanılacak ilgili MKAnnotation verileri sağlandırabilirsiniz. Haritaya ek açıklama eklemek için aşağıdaki AddAnnotation kodda gösterildiği gibi MKMapView bir örneğin yöntemini çağırmanız gerekir:
//an arbitrary coordinate used for demonstration here
var sampleCoordinate =
new CLLocationCoordinate2D (42.3467512, -71.0969456); // Boston
//create an annotation and add it to the map
map.AddAnnotation (new SampleMapAnnotation (sampleCoordinate));
Buradaki harita değişkeni, eşlemenin kendisini MKMapView temsil eden sınıf olan bir örneğidir. MKMapView, ek açıklama görünümünü haritada CoordinateSampleMapAnnotation konumlandırmak için örnekten türetilen verileri kullanır.
Protokol, tüketicinin (bu durumda harita) uygulama ayrıntılarını bilmek zorunda kalmadan, onu uygulayan tüm nesneler arasında bilinen bir MKAnnotation özellik kümesi sağlar. Bu, bir haritaya çeşitli olası ek açıklamalar eklemeyi kolaylaştırıyor.
Protokollere Derinlemesine Inma
C# arabirimleri isteğe bağlı yöntemleri desteklemez, Xamarin.iOS protokolleri soyut sınıflara eşler. Bu nedenle, 'de bir protokolün benimsenme, Xamarin.iOS'ta protokole bağlı soyut sınıftan türetilen ve gerekli yöntemlerin Objective-C uygulanmasıyla uygulanır. Bu yöntemler sınıfında soyut yöntemler olarak ortaya çıkar. Protokolden gelen isteğe bağlı yöntemler C# sınıfının sanal yöntemlerine bağlanacak.
Örneğin, UITableViewDataSource Xamarin.iOS'ta bağlı olarak protokolün bir kısmı şu şekildedir:
public abstract class UITableViewDataSource : NSObject
{
[Export ("tableView:cellForRowAtIndexPath:")]
public abstract UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath);
[Export ("numberOfSectionsInTableView:")]
public virtual int NumberOfSections (UITableView tableView){...}
...
}
sınıfının soyut olduğunu unutmayın. Xamarin.iOS, protokollerde isteğe bağlı/gerekli yöntemleri desteklemek için sınıfı soyut yapar. Ancak, Objective-C protokollerin (veya C# arabirimlerin) aksine, C# sınıfları birden çok devralmayı desteklemez. Bu, protokolleri kullanan ve genellikle iç içe geçmiş sınıflara yol açan C# kodunun tasarımını etkiler. Bu sorun hakkında daha fazla bilgi, bu belgenin ilerleyen kısımlarında Temsilciler bölümünde ele almaktadır.
GetCell(…), protokolünün gerekli bir yöntemi Objective-CGetCell(…)seçiciye tableView:cellForRowAtIndexPath: bağlı soyut bir UITableViewDataSource yöntemdir. Seçici, yöntem Objective-C adı terimidir. Xamarin.iOS, yöntemi gereken şekilde uygulamak için soyut olarak bildirmektedir. Diğer yöntem olan NumberOfSections(…) , 'a bağımlıdır. numberOfSectionsInTableview: Bu yöntem protokolde isteğe bağlıdır, bu nedenle Xamarin.iOS bunu sanal olarak bildirerek C# ile geçersiz kılma isteğe bağlıdır.
Xamarin.iOS sizin için tüm iOS bağlamalarını sizin için hazırlar. Ancak, el ile bir protokol bağlamanız gerekirse, bunu ile Objective-C bir sınıf dekore ile ExportAttribute yapabilirsiniz. Bu, Xamarin.iOS tarafından kullanılan yöntemle aynıdır.
Objective-CXamarin.iOS'ta türleri bağlama hakkında daha fazla bilgi için makalesine Binding Objective-C Types bakın.
Ancak protokolleri henüz tamamlayamadık. Ayrıca, temsilciler için temel olarak iOS'ta da Objective-C kullanılır. Bu, sonraki bölümün konusudur.
Temsilciler
Objective-CiOS, temsilci desenini uygulamak için temsilciler kullanır ve bu düzende bir nesne başka bir nesneye geçirilsin. İş yapan nesne, ilk nesnenin temsilcisidir. Nesne, temsilciye belirli şeyler olduktan sonra ileti göndererek iş yapmalarını söyler. içinde bunun gibi bir ileti Objective-C göndermek, işlevsel olarak C# içinde bir yöntemi çağırmaya eşdeğerdir. Temsilci bu çağrılara yanıt olarak yöntemleri uygulayan bir temsilcidir ve bu nedenle uygulamaya işlevsellik sağlar.
Temsilciler, alt sınıflar oluşturmak zorunda kalmadan sınıfların davranışını genişletmeye olanak sağlar. iOS uygulamaları, önemli bir eylem meydana geldiğinde genellikle bir sınıf başka bir sınıfa geri çağıran temsilciler kullanır. Örneğin, kullanıcı bir harita üzerinde ek açıklamaya dokunarak temsilci sınıfının yazarına uygulama içinde yanıt verme fırsatı veren sınıf, temsilcisine MKMapView geri çağrır. Bu makalenin devamlarında Xamarin.iOS ile Temsilci Kullanma makalesinde bu tür bir temsilci kullanımı örneği üzerinde çalışabilirsiniz.
Bu noktada, bir sınıfın temsilcide hangi yöntemlerin çağrıl olacağını nasıl belirleyeceklerini merak ediyor olabilirsiniz. Burası, protokolleri kullanabileceğiniz başka bir yerdir. Genellikle, temsilci için kullanılabilen yöntemler benimseyen protokollerden gelir.
Protokoller Temsilcilerle Nasıl Kullanılır?
Daha önce protokollerin haritaya ek açıklama eklemeyi desteklemek için nasıl kullanıldıklarını gördük. Protokoller, belirli olaylar ortaya çıktıktan sonra çağrılacak sınıfların bilinen bir yöntem kümesi sağlamak için de kullanılır. Örneğin kullanıcı bir eşlem üzerinde ek açıklamaya dokunarak veya tablodaki bir hücreyi seçer. Bu yöntemleri uygulayan sınıflar, onları çağıran sınıfların temsilcileri olarak bilinir.
Temsilci seçmeyi destekleyen sınıflar, temsilciyi uygulayan bir sınıfın atandığı Bir Temsilci özelliğini ortaya çıkararak bunu yapar. Temsilci için uygulayan yöntemler, belirli bir temsilcinin benimseyen protokole bağlıdır. yöntemi için protokolünü, yöntemi için, bir temsilciyi açığa çıkarmak istediğiniz iOS genelindeki diğer sınıflar için , ve gibi UITableViewUITableViewDelegate yöntemlerini UIAccelerometerUIAccelerometerDelegate uygulayabilirsiniz.
Önceki örneğimizde gördüğümüz sınıf, çeşitli olaylar meydana geldikten sonra çağıracak MKMapView Temsilci adlı bir özellige de sahip. için Temsilci MKMapViewMKMapViewDelegate türündedir.
Bu seçeneği kısa bir süre içinde bir örnekte kullanarak ek açıklamayı seçtikten sonra yanıt ve ardından güçlü ve zayıf temsilciler arasındaki farkı ele alayacağız.
Güçlü Temsilciler ve Zayıf Temsilciler
Şu ana kadar baktığımız temsilciler güçlü temsilciler, yani kesin olarak yazıldılar. Xamarin.iOS bağlamaları, iOS'ta her temsilci protokolü için kesin türü kesin olarak türü kesin olan bir sınıfla birlikte sevk edildi. Ancak iOS'un zayıf temsilci kavramı da vardır. iOS, belirli bir temsilci için protokole bağlı bir sınıfı alt sınıfa eklemek yerine, NSObject nesnesinden türetilen herhangi bir sınıfta protokol yöntemlerini kendiniz bağlamayı, yöntemlerinizi ExportAttribute ile dekore edinerek ve ardından uygun seçicileri Objective-C sağlar. Bu yaklaşımı benimserken, sınıf örneğinizi Delegate özelliği yerine WeakDelegate özelliğine atarız. Zayıf bir temsilci size temsilci sınıfını farklı bir devralma hiyerarşisinde aşağı alma esnekliği sunar. Şimdi hem güçlü hem de zayıf temsilciler kullanan bir Xamarin.iOS örneğine bakalım.
Xamarin.iOS ile Temsilci Kullanma Örneği
Örneğimizde ek açıklamaya dokunan kullanıcıya yanıt olarak kod yürütmek için alt sınıfa ekleyebilir ve özelliğinin özelliğine MKMapViewDelegateMKMapView bir örnek Delegate atayabilirsiniz. Protokol MKMapViewDelegate yalnızca isteğe bağlı yöntemler içerir.
Bu nedenle, tüm yöntemler Xamarin.iOS sınıfında bu protokole bağlı olan MKMapViewDelegate sanaldır. Kullanıcı bir ek açıklamayı seçerse MKMapView örnek iletiyi mapView:didSelectAnnotationView: temsilcisine gönderir. Xamarin.iOS'ta bunu işlemek için MKMapViewDelegate alt sınıfında yöntemini şu DidSelectAnnotationView (MKMapView mapView, MKAnnotationView annotationView) şekilde geçersiz kılmamız gerekir:
public class SampleMapDelegate : MKMapViewDelegate
{
public override void DidSelectAnnotationView (
MKMapView mapView, MKAnnotationView annotationView)
{
var sampleAnnotation =
annotationView.Annotation as SampleMapAnnotation;
if (sampleAnnotation != null) {
//demo accessing the coordinate of the selected annotation to
//zoom in on it
mapView.Region = MKCoordinateRegion.FromDistance(
sampleAnnotation.Coordinate, 500, 500);
//demo accessing the title of the selected annotation
Console.WriteLine ("{0} was tapped", sampleAnnotation.Title);
}
}
}
Yukarıda gösterilen SampleMapDelegate sınıfı, örneği içeren denetleyicide iç içe geçmiş bir sınıf olarak MKMapView uygulanır. içinde, Objective-C genellikle denetleyicinin doğrudan sınıfının içinde birden çok protokolü benimseyenleri görüyorsunuz. Ancak protokoller Xamarin.iOS'ta sınıflara bağlı olduğu için, kesin olarak türü kesin olarak yazlanmış temsilciler uygulayan sınıflar genellikle iç içe geçmiş sınıflar olarak dahil edilir.
Temsilci sınıfı uygulaması yerindeken, yalnızca denetleyicide temsilcinin bir örneğini örneği örneği gerekir ve bunu burada gösterildiği gibi MKMapView 'nin Delegate özelliğine atamanız gerekir:
public partial class Protocols_Delegates_EventsViewController : UIViewController
{
SampleMapDelegate _mapDelegate;
...
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
//set the map's delegate
_mapDelegate = new SampleMapDelegate ();
map.Delegate = _mapDelegate;
...
}
class SampleMapDelegate : MKMapViewDelegate
{
...
}
}
Aynı şeyi gerçekleştirmek için zayıf bir temsilci kullanmak için, yönteminden türetilen herhangi bir sınıfta kendiniz bağlamanız ve özelliğine NSObjectWeakDelegate atamanız MKMapView gerekir. Sınıf UIViewController sonuçtan türetilsin NSObject (CocoaTouch'daki her sınıf gibi), doğrudan denetleyicide bağlı bir yöntem uygulayarak denetleyiciyi 'nin sınıfına atayabilirsiniz. Bu yöntem, fazladan iç içe geçmiş sınıfa ihtiyaçtan Objective-CmapView:didSelectAnnotationView:MKMapViewWeakDelegate kaçınabilirsiniz. Aşağıdaki kodda bu yaklaşım gösterilmiştir:
public partial class Protocols_Delegates_EventsViewController : UIViewController
{
...
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
//assign the controller directly to the weak delegate
map.WeakDelegate = this;
}
//bind to the Objective-C selector mapView:didSelectAnnotationView:
[Export("mapView:didSelectAnnotationView:")]
public void DidSelectAnnotationView (MKMapView mapView,
MKAnnotationView annotationView)
{
...
}
}
Bu kodu çalıştırarak, uygulama kesin olarak türü kesin olarak yazmış temsilci sürümünü çalıştırarak tam olarak aynı şekilde davranır. Bu kodun avantajı zayıf temsilcinin türü kesin olarak yazılan temsilciyi kullandığımız zaman oluşturulan ek sınıfın oluşturulmasını gerektirmesidir. Ancak, bu tür güvenliğin bir masrafı olarak gelir. 'a geçirilen seçicide bir hata yaptıysanız, çalışma zamanının sonuna ExportAttribute kadar bunu bulamazdı.
Olaylar ve Temsilciler
Temsilciler, .NET'in olayları kullanma örneğine benzer şekilde iOS'ta geri çağırmalar için kullanılır. iOS API'lerini ve temsilci kullanmalarını .NET gibi göstermek için Objective-C Xamarin.iOS, temsilcilerin iOS'ta kullanıldıkları birçok yerde .NET olaylarını ortaya çıkarır.
Örneğin, seçili bir ek açıklamaya yanıt veren önceki uygulama, bir .NET olayı kullanılarak MKMapViewDelegate Xamarin.iOS'ta da uygulanıyor olabilir. Bu durumda, olayı içinde tanımlanır ve MKMapView olarak çağrılır. DidSelectAnnotationView türünde bir EventArgs alt sınıfı MKMapViewAnnotationEventsArgs olabilir. özelliği, burada gösterildiği gibi daha önce sahip olduğunuz uygulamayla devam etmek için ek açıklama görünümüne ViewMKMapViewAnnotationEventsArgs bir başvuru sağlar:
map.DidSelectAnnotationView += (s,e) => {
var sampleAnnotation = e.View.Annotation as SampleMapAnnotation;
if (sampleAnnotation != null) {
//demo accessing the coordinate of the selected annotation to
//zoom in on it
mapView.Region = MKCoordinateRegion.FromDistance (
sampleAnnotation.Coordinate, 500, 500);
//demo accessing the title of the selected annotation
Console.WriteLine ("{0} was tapped", sampleAnnotation.Title);
}
};
Özet
Bu makalede Xamarin.iOS'ta olayların, protokollerin ve temsilcilerin nasıl kullanılası elelanmıştır. Xamarin.iOS'un denetimler için normal .NET stili olayları nasıl ortaya çıkararak ortaya çıkar olduğunu gördük. Daha sonra, C# arabirimlerinden nasıl farklı olduğu ve Xamarin.iOS'un bunları nasıl kullandığı da dahil olmak üzere Objective-C protokoller hakkında bilgi öğrendik. Son olarak, Objective-C Xamarin.iOS perspektifinden temsilcileri inceledik. Xamarin.iOS'un hem güçlü hem de zayıf türe sahip temsilcileri nasıl desteklediğini ve .NET olaylarını temsilci yöntemlerine bağlamayı gördük.

