[iPhone][MonoTouch] 첫번째 샘플 : MinutesToMidnight

Apps Amuck의 첫째날 예제 "Minutes To Midnight"를 MonoTouch로 구현해 봤습니다. 어플리케이션은 자정까지 얼마나 남았는지 보여주는 것입니다. 

원 사이트의 설명이 그리 자세하지 않았지만, 큰 어려움(?) 없이 구현할 수 있었습니다.
iPhone SDK의 클래스를 대부분 이용이 가능한 듯 하나 일부 함수들의 이름이나 파라미터들이 C#에 적당하게 변경되어 있기 때문에 주의가 필요합니다. 




시작해 보겠습니다. 일본어 맥북이라서 메뉴가 일본어로 나오고 있지만, 메뉴 위치가 다르거나 한 것이 아니기 때문에 어려움은 없으리라 생각합니다.

1. 솔루션 생성 : "MinutesToMidnight"이름으로 새 솔루션을 생성합니다.
솔루션 생성에 문제가 없다면 아래와 같은 기본 파일이 생성 됩니다. "Main.cs"는 AppDelegate가 구현되어 있는 파일입니다. "MainWindow.xib"는 XCode의 InterfaceBuilder를 통해 UI를 꾸밀 수 있는 파일입니다. xib파일로부터 C#용  클래스 파일을 자동으로 생성된 "MainWindow.xib.designer.cs" 파일이 있습니다. "MainWindow.xib"파일에 변경이 생기면 자동으로 관련 cs파일이 수정되도록 되어 있습니다. 

2. 뷰xib파일과 연결된 컨트롤러를 생성합니다. 방법은 [새 파일 추가]를 선택, iPhone항목에서 "View Interface Definition with Controller"를 선택하면 됩니다.
"MinutesToMidnightViewController"이름으로 생성된 파일이 3개가 추가 되었음을 확인 할 수 있습니다. "~.xib.cs"는 xib파일에 대해서 이벤트등을 구현하기 위한 파일입니다. 
3. InterfaceBuilder를 이용한 UI 구성은 크게 다르지 않습니다. 다만 각 UI요소를 연결하는 Outlet 변수 선언을 IB에서 직접 작업하는 것이 차이가 있습니다. UIViewController를 "MinutesToMidnightViewController"이름으로 추가합니다.
추가한 컨트롤러를 AppDelegate에서 사용하기 위한 Outlet변수 선언을 합니다. "App Delegate Identiry"윈도우에서 "Class Outlets" 항목의 [+]를 클릭하여 추가 합니다. "viewController"이름이며 타입은 "MinutesToMidnightViewController" 입니다.
추가한 Outlet의 viewController를 연결합니다. 아래 화면은 연결 후의 모습입니다.
4. 시간을 표시하기 위한 UILabel을 View Controller에 추가하고, 위와 같은 방법으로 Outlet변수를 만듭니다.  UILabel타입의 "countdownLabel"이름으로 추가 했습니다. 실제 UILabel과 연결을 합니다.
여기까지 하고 저장하고 Interface Builder를 종료 합니다. 

5. "MainWindow.xib"로부터 생성되는 "MainWindow.xib.designer.cs" 소스 입니다. 
namespace MinutesToMidnight {
// Base type probably should be MonoTouch.Foundation.NSObject or subclass
[MonoTouch.Foundation.Register("AppDelegate")]
public partial class AppDelegate {

[MonoTouch.Foundation.Connect("window")]
private MonoTouch.UIKit.UIWindow window {
get {
return ((MonoTouch.UIKit.UIWindow)(this.GetNativeField("window")));
}
set {
this.SetNativeField("window", value);
}
}

[MonoTouch.Foundation.Connect("viewController")]
//private MonoTouch.UIKit.UIViewController viewController {
private MinutesToMidnightViewController viewController { // <- 이부분을 수정해 주세요.
get {
//return ((MonoTouch.UIKit.UIViewController)(this.GetNativeField("viewController")));
return ((MinutesToMidnightViewController)(this.GetNativeField("viewController"))); // <- 이부분을 수정해 주세요.
}
set {
this.SetNativeField("viewController", value);
}
}
}

// Base type probably should be MonoTouch.UIKit.UIViewController or subclass
[MonoTouch.Foundation.Register("MinutesToMidnightViewController")]
public partial class MinutesToMidnightViewController {

[MonoTouch.Foundation.Connect("countdownLabel")]
private MonoTouch.UIKit.UILabel countdownLabel {
get {
return ((MonoTouch.UIKit.UILabel)(this.GetNativeField("countdownLabel")));
}
set {
this.SetNativeField("countdownLabel", value);
}
}
}

}
자동으로 생성 된 클래스 소스 입니다만 수정이 필요합니다. "수정"이라고 주석 처리한 부분을 확인 하고 수정합니다. 뷰 컨트롤러에 대해 작업한 내용이 반영 되어 있는 것을 확인 할 수 있습니다. Outlet변수등이 선언 되어 있습니다. 

6. Main.cs 소스를 수정합니다. 여기서는 NSTimer 사용 방법과 이벤트 함수 이름에 차이가 있으니 주의 할 필요가 있습니다. AppDelegate의 멤버 변수로 NSTimer를 선언 합니다. 주기적인 이벤트를 처리하기 위해 publc void OnTimer()함수도 추가 합니다. 
namespace MinutesToMidnight
{
public class Application
{
static void Main (string[] args)
{
UIApplication.Main (args);
}
}

// The name AppDelegate is referenced in the MainWindow.xib file.
public partial class AppDelegate : UIApplicationDelegate
{
NSTimer timer;
// This method is invoked when the application has loaded its UI and its ready to run
// Xcode에서 대칭되는 이름은 "applicationDidFinishLaunching"입니다.
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
// Xcode에선 아래와 같이 선언 하고 있습니다.
// timer = [NSTimer scheduledTimerWithTimeInterval:(1.0) target:self selector:@selector(onTimer) userInfo:nil repeats:YES];
// C#코드에선 NSTimer객체를 생성하는 함수가 다양하게 있습니다.

timer = NSTimer.CreateRepeatingScheduledTimer(new TimeSpan(1000), OnTimer);
// If you have defined a view, add it here:
window.AddSubview (viewController.View); // <- 추가한 뷰 컨트롤러의 뷰를 메인 윈도우에 추가 합니다.

window.MakeKeyAndVisible ();

return true;
}

// This method is required in iPhoneOS 3.0
public override void OnActivated (UIApplication application)
{
}

// Xcode에서 대칭되는 이름은 "applicationWillTerminate"입니다.
public override void WillTerminate (UIApplication application)
{
timer.Invalidate();
base.WillTerminate (application);
}

public void OnTimer()
{
viewController.updateLabel();
}
}
}
NSTimer.CreateRepeatingScheduledTimer(new TimeSpan(1000), OnTimer) 를 통해 NSTimer객체를 생성합니다. TimeSpan은 C#에서 제공하는 시간과 관련된 클래스 입니다. 1000은 ms단위로 1초 간격으로 타이머 이벤트를 발생 시킵니다. OnTimer는 발생한 이벤트를 처리하는 함수입니다. 여기서는 뷰 컨트롤러의 updateLabel함수를 호출하고 있습니다. 

7. MinutesToMidnightViewController.xib.designer.cs의 소스를 살펴 보겠습니다. 크게 수정할 부분은 없지만 MainWindow.xib.designer.cs와 충돌을 일으키는 부분이 있습니다.  그부분을 주석으로 막아 주시면 됩니다. MonoTouch의 버그인지 같은 문제가 항상 반복되는 듯 보입니다.
namespace MinutesToMidnight
{
// Base type probably should be MonoTouch.UIKit.UIViewController or subclass
//[MonoTouch.Foundation.Register("MinutesToMidnightViewController")] // <- 이부분을 주석처리 했습니다.
public partial class MinutesToMidnightViewController
{

[MonoTouch.Foundation.Connect("view")]
private MonoTouch.UIKit.UIView view {
get { return ((MonoTouch.UIKit.UIView)(this.GetNativeField ("view"))); }
set { this.SetNativeField ("view", value); }
}
}
}
8. 마지막으로 화면 처리를 담당하는 MinutesToMidnightViewController.xib.cs소스를 살펴 보겠습니다.  시간을 표시하기 위한 updateLabel함수를 추가 하고 아래 소스의 코드를 입력합니다. 레이블의 폰트를 ViewDidLoad 이벤트에서 설정했습니다. Xcode와는 차이가 있으니 주의 해 주세요.
namespace MinutesToMidnight
{
public partial class MinutesToMidnightViewController : UIViewController
{
#region Constructors

// The IntPtr and NSCoder constructors are required for controllers that need
// to be able to be created from a xib rather than from managed code

public MinutesToMidnightViewController (IntPtr handle) : base(handle)
{
Initialize ();
}

[Export("initWithCoder:")]
public MinutesToMidnightViewController (NSCoder coder) : base(coder)
{
Initialize ();
}

public MinutesToMidnightViewController ()
{
Initialize ();
}

void Initialize ()
{
}

#endregion

public override void ViewDidLoad ()
{
// 아래 폰트 생성 하는 방법에 차이가 있습니다.
// Xcode는 "[countdownLabel setFont:[UIFont fontWithName:@"DBLCDTempBlack" size:128.0]];" 입니다.
countdownLabel.Font = UIFont.FromName("DBLCDTempBlack", 128.0f);
base.ViewDidLoad ();
}

public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
// 아래 코드와 대칭되는 Xcode는 "return (interfaceOrientation == UIInterfaceOrientationPortrait);" 입니다.
return (toInterfaceOrientation == UIInterfaceOrientation.Portrait);
//return base.ShouldAutorotateToInterfaceOrientation (toInterfaceOrientation);
}

public void updateLabel()
{
// C#에서 사용하는 날짜를 구하기 위한 클래스와 그 사용 방법입니다.
DateTime now = DateTime.Now;

int hour = 24 - now.Hour;
int min = 59 - now.Minute;
int sec = 59 - now.Second;

// C#의 String.Format 문법입니다.
countdownLabel.Text = String.Format("{0:D2}:{1:D2}:{2:D2}", hour, min, sec);
}
}
}
필요한 작업은 모두 마쳤습니다. 
9. 컴파일 후 실행 시킨 화면 입니다.
MonoTouch로 개발할 때 주의 해야할 가장 큰 것은 Xcode/iPhone SDK에서 사용되는 함수들의 이름이 약간씩 틀린 것과 객체 생성시 사용되는 인수등이 차이가 있는 것입니다.  C#에 맞게 수정된 것이기 때문이라고 생각합니다. 평가판이어서 그런지는 모르겠지만 제공되는 문서가 많이 부족합니다. 앞으로 개선되어야 할 점이겠습니다.

반대로 C#에서 제공하는 다양한 클래스들을 사용할 수 있는 것은 큰 장점이라고 생각합니다.  ZuneHD라는 MS에서 개발한 게임기용 게임 개발을 위한 XNA라이브러리도 MonoTouch용으로 포팅이 되어 테스트 중이기 때문에 게임 개발에도 큰 역할을 할 수 있을 것 같습니다. 

기본적으로 제공되는 것 이외의 샘플을 만들어 보려고 했는데, 시행착오가 많네요. Apps Amuck의 예제만이라도 전부 MonoTouch용으로 구현해 봐도 상당한 도움이 될 것 같습니다.


by 연서아빠 | 2009/09/27 00:57 | iPhone | 트랙백 | 덧글(0)

트랙백 주소 : http://neojjang.egloos.com/tb/1952677
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]

:         :

:

비공개 덧글

◀ 이전 페이지 다음 페이지 ▶