Download - Cocoa勉強会20140621 macとiosで共通のコード
MacとiOSで共通のビューを使う
2014.6.21 Cocoa勉強会 関西
大森智史 @oogon / satoshi.oomori
あんた、誰?
• と、いうわけで自己紹介。
• 大森智史といいます。
• 某印刷会社勤務。
• Cocoa勉強会関西は第0回からいます。
• ブログあります。
• こんなのも始めました。
XOJOニュース
• まもなく、iOSビルド機能が登場(Mac版のみ)
• 第53回でご紹介しましたXOJO
今日の話
• 前回、ゲームの話をした時、敵キャラの動きを編集するツールが、わりと好評だったので、公開することに。
今日の話
• 最初iPad用に作りましたが、途中からMac用として作り変えました。
• 今日はその際の話を
とりあえず宣伝
motion editor
• SpriteKitのSKActionで使えるモーション記述用のベジェエディタをMacApp Storeで公開中(Ver 1.0.1)
https://itunes.apple.com/jp/app/motion-editor/id876088092
motion editor
• v1.1で追加される機能
• 線のエクスポート、インポート
• アンドゥ(リドゥはまだ…)
motion editor
• 手書きベジェ
• 現在の編集モードを表示
• その他もろもろインターフェースの改善
motion editor• Ver 1.1 リリース
TODAY• 発表終了後
motion editor
• Swiftコードの書き出し(審査通りました!)
• (サンプル出せないので困ってるけど…)
世界初たぶん
motion editor
• 今はまだ無料です。
• https://itunes.apple.com/jp/app/motion-editor/id876088092
• http://cocoaapi.hatenablog.com/entry/motion_editor_Japanese_support_page
motion editor
• レビューお待ちしております。
デモ
それでは、本題に
「共通のビュー」
なぜ必要か
• 複雑な描画をするビューのコードの共通化
• コード作成量の削減
• 同一の描画を実現
なぜ必要か
• ようするに、同じようなものを作るの面倒
どんな場合
• ゲーム ゲーム本体と編集ツール
• 電子書籍 表示とエディタ
• グラフィックツール 表示とエディタ
方針
• ボタン、メニューなどはそれぞれのUIパーツを使う
• メインビューのみ共通にする
2つの方式
• CoreGraphicsを使う
MacとiOSではY座標が違うので注意
• Spritekitを使う
ピクセルのみの描画の場合はこちらかな
iOS 8,OS X 10.10
• Scene KitがついにiOSにも!
• OS X版は以前ご紹介しました。
• http://www.slideshare.net/oogon/scene-kit-cocoa201306
CoreGraphics
• 今回はCoreGraphicsを使いました。
相違点
• 似たクラスでも微妙に違うものあり
• 今回使った中から違うところをピックアップしてみました。
Bezier
• NSBezierPathとUIBezierPath
• メソッド名が違う
Color
• NSColorとUIColor
• かなり似通ったメソッド名だけどクラス名が違う
NSValue
• point構造体を得るにもいちいち違う
• pointValue (Mac)
• CGPointValue (iOS)
Undo Redo
• iOS側もNSUndoManager !
• (iOS側ではまだアンドゥは実装していないけど、エラーは出ない)
• まだiOS側で使っていないので、よくわからない
具体的な方法
プリプロセッサマクロ• 基本パターン
#if TARGET_OS_IPHONE
/*iOSでのみ行う処理をゴニョゴニョ*/
#elif TARGET_OS_MAC
/*Macでのみ行う処理をゴニョゴニョ*/
#endif
欠点
• コードが読みづらくなる
解決• それぞれを継承したサブクラスを作り同じメソッド名で呼び出せるように。(似たクラスがある場合)
• プリプロセッサマクロでの切り分けはクラス内で行う。
• これで、本体処理からはプリプロセッサマクロを排除
解決
• ただし…
• 数回しか出てこないようなところは、特に気にしない。
• 何回も出てくるところだけ独自のクラスを作る
• カスタムクラス OOOBezierPath
#if TARGET_OS_IPHONE + (OOOBezierPath *)bezierPathWithOvalInRect:(CGRect)rect { return (OOOBezierPath *)[super bezierPathWithOvalInRect:(CGRect)rect]; } #elif TARGET_OS_MAC + (OOOBezierPath *)bezierPathWithOvalInRect:(NSRect)rect { return (OOOBezierPath *)[super bezierPathWithOvalInRect:NSMakeRect(rect.origin.x, (rect.origin.y), rect.size.width, rect.size.height)]; } #endif
• カスタムクラス OOOColor
#if TARGET_OS_IPHONE @interface OOOColor : UIColor #elif TARGET_OS_MAC @interface OOOColor : NSColor #endif
• 呼び出し側
//フレーム枠描画 OOOBezierPath *framePath = (OOOBezierPath *)[OOOBezierPath bezierPathWithRect:CGRectMake(OFFSETX,OFFSETY,300.0f,450.0f)]; ![[OOOColor lightGrayColor] setFill]; ![framePath stroke];
OS Xの座標を逆に• iOSに合わせる
#if TARGET_OS_IPHONE #elif TARGET_OS_MAC //Macでは座標が反対になるのでフリップする - (BOOL)isFlipped { return YES; } #endif
• 実はすっかり忘れていたのでFBで教えてもらった
画面タッチ処理
• 今回は線の位置を指定できれば良いので、タッチ開始、ドラッグ、タッチ終了のみ対応
画面タッチ
• OS X mouseDown:
• iOS touchesBegan:withEvent:
• タッチ・マウスダウンのロケーションは共通なので、CGPointにして、共通処理のメソッドへ
画面ドラッグ
• OS X mouseDrag:
• iOS touchesMoved:withEvent:
• タッチ・マウスダウンのロケーションは共通なので、CGPointにして、共通処理のメソッドへ
タッチ終了
• OS X mouseUp:
• iOS touchesEnded:withEvent:
• タッチ・マウスダウンのロケーションは共通なので、CGPointにして、共通処理のメソッドへ
• プラットフォーム依存部分 今回はタッチ(クリック)のロケーションだけを渡す
#if TARGET_OS_IPHONE - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [[event allTouches] enumerateObjectsUsingBlock:^(id obj, BOOL *stop) { [self touchBeganAndMuseDown:CGPointMake([obj locationInView:self].x,[obj locationInView:self].y)]; *stop = YES; }]; } #elif TARGET_OS_MAC - (void)mouseDown:(NSEvent *)theEvent { NSPoint mouseLoc; mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil]; [self touchBeganAndMuseDown:CGPointMake(mouseLoc.x,mouseLoc.y)]; !} #endif
• 共通処理部分
-(void)touchBeganAndMuseDown:(CGPoint)touchPoint { //マウスダウンやタッチした時の共通処理 NSInteger loopCount = 0; touchBegin = touchPoint; OOOAppDelegate *appDelegate = [self myDelegate]; NSMutableArray *pathObjects = [appDelegate pathObjects]; !!
…(共通の処理を行なう) } !}
needsDisplay
!
-(void)needsDisplay { #if TARGET_OS_IPHONE [self setNeedsDisplay]; #elif TARGET_OS_MAC [self setNeedsDisplay:YES]; #endif }
delegate!
-(OOOAppDelegate *)myDelegate { #if TARGET_OS_IPHONE return (OOOAppDelegate *)[[UIApplication sharedApplication] delegate]; #elif TARGET_OS_MAC return (OOOAppDelegate *)[[NSApplication sharedApplication] delegate]; #endif }
まとめ
• あんまり使わないところはプリプロセッサマクロ。
• 何度も使うところは共通のメソッドやクラスを作って、そこでプラットフォームの切り分けをする。
まとめ
• iOSで何か作るときの編集ツールは、Macで動かせると何かと便利です。
いまOS Xアプリがアツい!
ありがとうございました