Hello World pro MonoTouch
Pokud chceme vyvíjet jakoukoliv aplikaci pro jakýkoliv produkt Apple, je třeba ji vyvíjet v operačním systému Mac OS X. Dále potřebujeme mít naistalovány:
-
Xcode 4 – je IDE(Integrated Development Environment) pro vývoj aplikací pro produkty Apple, je ho možné získat na OS X App Store, a pouze pokud máme koupený vývojářský profil od Apple. S Xcode získáme také SDK knihoven, přístup do dokumentace a simulátory Apple mobilních zařízení.
-
Mono Framework – je možné stáhnout z oficiálních webových stránek Mono projektu.
-
MonoDevelop – je IDE pro vývoj Mono aplikací
-
MonoTouch
Apple zakazuje ve svých aplikacích mechanismy dovolující vykonávání dalšího kódu, což vylučuje nestandardní běhové systémy, JIT (just-in-time) kompilátory a interprety bytového kódu. Mono stejně jako .Net framework JIT kompilátor používá a až následně převádí bytový kód do vlastního kódu cílové platformy až v běhové fázi. Tento nepřekonatelný problém byl velkou výzvou pro vývojáře Mona. Naštěstí kompilátor Applu podporuje i alternativní model AOT (ahead-of-time), který převede do vlastního kódu cílové platformy jazyk .NET CIL (Common Intermediate Language – obecný zprostředkující jazyk) již v době kompilace. A takto lze Mono aplikace staticky zkompilovat do spustitelných souborů nevyžadujících virtuální stroje či jiné běhové komponenty zakazované Apple. Tento mechanismus už nyní využívá řada her pro iPhone postavených na 3D jádru Unity. To rovněž užívá AOT kompilaci a přijetí mnoha her s tímhle jádrem na App Store dokazuje, že Apple dané řešení považuje za přijatelné.
Správa paměti v Objective-C a v .Net frameworku je velmi odlišná. Objective-C totiž nemá garbage collector implementován stejně jako v .Net frameworku. Paměť pro objekty v Objective-C je ve starších verzích jazyka alokována a uvolňována manuálně. Až od verze 2.0 se používá strategie počítání referencí. Tato strategie uvolňování paměti není v praxi příliš efektivní, proto většina Apple programátorů uvolňuje paměť stále manuálně. MonoTouch sice implementovalo svůj garbabe collector, ale ten nereaguje s dostatečnou pružností. A proto všechny objekty v MonoTouch mají rozhraní IDisposable, aby mohl být každý objekt v MonoTouch uvolněn voláním funkce Disponse. iPhone má velice omezené zdroje a proto programátor musí být velice precizní při uvolňování paměti, ale pokud i přesto na nějaký objekt zapomenete, MonoTouch garbage collector se o něj postará.
Objective-C má vlastnost protocols. Protocols jsou velmi podobné rozhraním v .Net. Definují seznam metod, které třída implementuje, a třída může implementovat jakýkoliv počet protokolů. Je zde jedna důležitá odlišnost a to, že metody obsažené v protokolu nemusí být implementována v třídě, která tento protokol implementuje. MonoTouch to vyřešilo pomocí abstraktních tříd a virtuálních metod. Toto řešení není ideální jelikož .Net nepodporuje vícenásobnou dědičnost. Tento problém se vyřešil pomocí událostí. Virtuální metody, které jsou uvedeny ve více než jednom protokolu, publikují svoje volání pomocí událostí na svoje přepsané potomky. Tuto osvědčenou strategii MonoTouch používá k implementaci více vlastností Objective-C.
Nyní vytvoříme jednoduchou aplikaci s MonoTouch. Aplikace bude mít na úvodní obrazovce pouze jedno tlačítko, po kliknutí na toto tlačítko se objeví druhá obrazovka s textem, který bude obsahovat čas kdy bylo kliknuto na tlačítko. V MonoDevelop vytvoříme nový prázdný projekt, viz Obrázek 1.
V nastavení projektu lze nastavit verzi SDK jaký budeme používat, kde budeme projekt spouštět a také je zde nastaveni linkování projektu. Prázdný projekt obsahuje pouze tři soubory:
-
AppDelegate.cs – je delegát aplikace, který se stará o životní cyklus aplikace.
-
Main.cs – je vstupním bodem aplikace
-
Info.plist – je konfiguračním souborem aplikace
Každá obrazovka v iOS implementuje návrhový vzor Model View Controller, proto dále přidáme do projektu dva nové View Controllery, viz Obrázek 2:
-
MainViewController – toto bude úvodní obrazovka.
-
SecondViewController – bude druhá obrazovka, na kterou aplikace přejde po kliknutí na tlačítko.
Každý View Controller obsahuje tři soubory:
-
MainViewController.xib – obsahuje definici grafického rozhraní, něco jako xaml soubor ve WPF, tento soubor je třeba vytvořit v Xcode. Jde o to jen navrhnout grafické rozložení ovládacích prvků na obrazovce, viz Obrázek 3.
-
MainViewController.designer.cs – je definice rozhraní mezi aplikaci a grafickým rozhraním.
-
MainViewController.cs – je výkonný kód View Controlleru.
Dvojklikem otevřeme MainViewController.xib v Xcode, pomocí návrháře GUI přidáme tlačítko, stejně jako když vyvíjíme klasickou aplikaci v Objective-C. Na tlačítko přidáme ještě akci kliknutí. Přidávat na View Controllery můžeme dva typy objektů:
Outlets – jsou analogické k C# propertám.
Actions – jsou analogické k událostem ve WPF.
Po ukončení editace xib souboru v Xcode a po jeho uložení se můžeme pustit do psaní vlastního výkonného kódu. Po uložení se změny v xib souboru, vytvoření grafických prvků, outletů a akcí, projeví v našem MainViewController.designer.cs, jak je vidět na Příkladu 1.
using MonoTouch.Foundation; namespace Chapter2.MonoTouchApp { [Register ("MainViewController")] partial class MainViewController { [Outlet] MonoTouch.UIKit.UIButton Button { get; set; } [Action ("ButtonTapped:")] partial void ButtonTapped (MonoTouch.Foundation.NSObject sender); } }
Dále upravíme soubor AppDelegate.cs, viz Příklad 2, tak, aby se MainViewController zobrazil při startu aplikace.
using MonoTouch.Foundation; using MonoTouch.UIKit; namespace Chapter2.MonoTouchApp { [Register ("AppDelegate")] public partial class AppDelegate : UIApplicationDelegate { private UIWindow _window; private UINavigationController _navigationController; public override bool FinishedLaunching(UIApplication app, NSDictionary options) { _window = new UIWindow (UIScreen.MainScreen.Bounds); _navigationController = new UINavigationController(); _navigationController.PushViewController(new MainViewController(), false); _window.RootViewController = _navigationController; _window.MakeKeyAndVisible (); return true; } } }
Nyní musíme upravit MainViewController.cs, který definuje životní cyklus obrazovky. Toto chování se definuje pomocí přepisovaní virtuálních funkcí UIViewController rozhraní, viz Příklad 3. Funkce ViewDidLoad je zavolána po inicializaci všech Views, potom je možné provést nastavení zobrazených komponent na obrazovce. Ve funkci ButtonTapped je implementováno chování po kliknutí na tlačítko, vytvoříme instanci druhé obrazovky, pošleme čas stisku tlačítka a nakonec ji zobrazíme.
using System; using MonoTouch.Foundation; using MonoTouch.UIKit; namespace Chapter2.MonoTouchApp { public partial class MainViewController : UIViewController { public MainViewController() : base ("MainViewController", null) { } public override void ViewDidLoad() { base.ViewDidLoad (); Title = "Hello, iOS!"; Button.SetTitleColor(UIColor.Red, UIControlState.Normal); } partial void ButtonTapped(NSObject sender) { NavigationController.PushViewController( new SecondViewController(DateTime.Now.ToLongTimeString()), true); } } }
Poslední, co je třeba udělat, je upravit SecondViewController.cs, přidat mu vlastnost, přes kterou budeme předávat řetězec s časem stisku tlačítka a nastavit text labelu tak, aby tento řetězec zobrazil, viz Příklad 4.
using MonoTouch.UIKit; namespace Chapter2.MonoTouchApp { public partial class SecondViewController : UIViewController { private readonly string _text; public SecondViewController(string text) : base ("SecondViewController", null) { _text = text; } public override void ViewDidLoad() { base.ViewDidLoad (); Title = "Second View"; ReceivedText.Text = _text; } } }
Aplikace můžeme nyní už spustit. Z MonoDevelop můžeme aplikaci spustit v simulátoru, viz Obrázek 4, nebo přímo do iPhone nebo iPad zařízení. Simulátor sice dokáže nasimulovat většinu funkcí Apple zařízení, ale některé funkce ano, jako např. ovládání více prsty, akcelerometer, lokalizaci, a jiné. Proto je někdy dobré testovat aplikace využívající tyto funkce přímo na zařízení.