Touch Bar シミュレータをiPadに表示して使用できるアプリをリリースしました。

この度、J-Tech Creations, Inc.から、Macの操作をiPadで行うことができるアプリをリリースしました。Xcodeで表示されるTouch BarをiPad上に表示して、使用することのできる機能も持っています。

アプリのダウンロード先は以下の通りです。

説明ビデオは以下のものです。

Mac側でもアプリをインストールして、MacのTouch Barの情報を送信する必要があります。J-Tech Creations, Inc サイトからMac版アプリをダウンロードすることができます。

AppStoreでも配信できるようにするために、汎用の画面操作アプリとして作成しています。Touch Barを使用するためには、最新のXcodeを起動して、WINDOW -> SHOW TOUCH BAR から、Touch Barを表示する必要があります。ですので、常時使用するためというよりも、開発のテスト用という感じと思います。ただ、iPad ProをMagic Keyboardの前に立てかけると、まさにTouch Barつきキーボードのようにしようできるので、気に入っています。

Apple製のアプリに関しては、すでにTouch Barに対応したアプリがリリースされているので、MacBook Proの検討中の方や、iMacでも使いたいという方にはオススメです。

オープンソースで同様のアプリがありますが、こちらのアプリは公開されているAPIを使用して作成しているので、自分でソースをビルドせずに、あプリを実行することができます。ですので、使用の際はXcodeを起動して、Xcode内のTouch Barシミュレータを起動しておく必要があります。

既知の問題

  1. シングルタッチしか送れないので、マルチタッチコントロールはできません
  2. 画像を送っているので、レスポンスはネイティブのアプリのようではありません
  3. フルスクリーンになると、タッチイベントがうまく送られないので、操作がうまくいきません
  4. Karabiner Elementなどで、キーに割り込んでいる場合、画面の輝度を変えるなどの機能がうまく動かない場合があります。

面白そうと思われたら、ぜひ使ってみていただければと思います。

#fukuObjC 福岡Swift&Obj-C&Xcode開発周り勉強会 – 0x02 で話してきました

Swift&Obj-C&Xcode開発周り勉強会 – 0x02 の実況ツイートまとめ #fukuObjC – Togetterまとめ

久しぶりにiOS開発の勉強会に出てみようということで、福岡では出たことなかったのですが参加してみました。

Swift&Obj-C&Xcode開発周り勉強会 – 0x02 on Zusaar

せっかくですので新しいものをやってみて登壇しようと思い、関心のあったReactiveCocoaの勉強してサンプルアプリを作って、iOSアプリを綺麗に作る方法についてまとめてみました。

ReactiveCocoaは面倒ですけど、ちゃんと作れば良いプログラムが出来るのは間違いないのでどんどん取り込んでいきたいと思います。SwiftでのFRPも調査していきたいですね。

福岡の勉強会初めてでましたが、他の発表も面白かったです。Swiftはこういう勉強会で軽く見ながら実践投入する段階で一気に勉強するのが良さそう。いかに公開してくださったスライドのリンクを置いておきます。

はなだ_のぶかず (nobkz)さん

uounɹɐʇ (tarunon)さん
NSUserDefaults噺

くろねこまいける (kuronekomichael)さんの発表もそれぞれ良かった。スライドが上がったら追記します。

CocoaPodsのプロジェクトで、ヘッダーファイルが読め込めない時の対処方法

1つのプロジェクトに複数のターゲットを作成している時に起きる問題のようで引っかかったのでメモ。

File not found エラー
File not found エラー

cocoaPodsを導入して、podsで導入したフレームワークのヘッダーファイルが読めずに、

19:9: fatal error: ‘RestKit/RestKit.h’ file not found

のようなエラーが出ました。
“CocoaPodsのプロジェクトで、ヘッダーファイルが読め込めない時の対処方法” の続きを読む

コードからUIWebViewをスクロールさせる方法

昔は難しかったのですが、iOS5から、UIWebViewがscrollViewをプロパティで持つようになったので簡単になった!オフセットしすぎると中身が見えなくなってしまうので、maxOffset以下にするのがポイント。
スクロールダウン(一度に画面の1/3)

float maxYOffset = self.webView.scrollView.contentSize.height - self.webView.scrollView.frame.size.height;
[wself.webView.scrollView setContentOffset:CGPointMake(self.webView.scrollView.contentOffset.x, MIN(self.webView.scrollView.contentOffset.y+self.webView.bounds.size.height/3.,maxYOffset)) animated:YES];

スクロールアップ
[wself.webView.scrollView setContentOffset:CGPointMake(self.webView.scrollView.contentOffset.x, MAX(self.webView.scrollView.contentOffset.y-self.webView.bounds.size.height/3.,0)) animated:YES];

このスクロールと、前の記事の編集中判定を使って、TweetOverviewでキーボードでスクロールダウン、スクロールアップ、cmd+wで詳細画面を閉じるというのを実装したのですが、外部キーボードと組み合わせると非常にいい感じです。審査して来週ぐらいにリリースされると思いますのでお楽しみに。

UIWebViewが編集中かを確かめる方法

UIWebViewが編集中かを確かめる方法がStackoverflowにもはっきりと分かりやすいのがなかったので備忘で書いておきます。UITextViewだと
[textView isFirstResponder]
で編集中か分かるのですが、UIWebViewの場合は、内部にある要素の一部が編集中になるため、webView自体のisFirstResponderはfalseが帰ってきます。
それで、再帰的に内部を確かめてどれか一つの要素が編集中かを確かめるメソッドがこちら。

使う時は、
if([webView isFirstResponderRecursive])
のように使うことが出来ます。

iOS 7 でAVSpeechSynthesizerを使用して音声を読み上げる

TweetOverviewの新機能の一つとして、音声読み上げ機能があります。最新のタイムライン上のツイートをsiriの声で自動で読み上げてくれるので、デスクサイドに置いておけば新しいツイートも分かりますし、関心ある論題かを知る事も出来ます。精度はまだいまいちですが、日本語で知っているトピックだと結構理解出来ます。
iTunes の App Store で配信中の iPhone、iPod touch、iPad 用 TweetOverview ツイート俯瞰デスクサイドアプリ

これは、iOS7で追加された、AVSpeechSynthesizer、AVSpeechUtteranceという機能を使用して作成しています。AVSpeechSynthesizerの方が実際に読み上げるオブジェクトで、AVSpeechUtteranceは読み上げる内容を定義したものです。
“iOS 7 でAVSpeechSynthesizerを使用して音声を読み上げる” の続きを読む

UIKit Dynamics を使用してViewを滑らかに移動する方法

TweetOverview 2.0.0 がリリースされました。
iTunes の App Store で配信中の iPhone、iPod touch、iPad 用 TweetOverview ツイート俯瞰デスクサイドアプリ

これまでのバージョンがiOS7でちょっと不具合があり、修正しようと思ったところ、ここもなおそう、あそこもなおそうとやっていたら、ほぼ書き直しになってしまいました。前バージョンではUITableViewを使用してスクロールしていたのですが、これがデータが多くなるとパフォーマンスも落ちますし、また検索ストリームにあまりにたくさんのツイートが入ってきた時に安定性が悪いという問題がなかなか解決しませんでした。
“UIKit Dynamics を使用してViewを滑らかに移動する方法” の続きを読む

UIImage の非透明部分だけを切り出す方法

Photoshopだと、非透明部分だけをトリムして切り取るのは簡単に出来ますが、UIImageに対しては、ちょっと面倒だったので備忘のために書いときます。

UIImage の切り取り自体は結構簡単なのですが、透明部分の判定が以外と面倒です。検索すると、wrep/UIImage-Trim ちょうど対応したUIImageカテゴリを発見。使ってみたのですが、どうもUIImageのScaleが2以上のときにうまく動いていないので対応。
tomohisa/UIImage-Trim
こちらにプロジェクトをforkして、scaleを考慮するように変更しました。

それに加えて、切り取る際にマージンを付ける機能も欲しかったので、


- (UIImage *) imageByTrimmingTransparentPixelsWithMargin:(UIEdgeInsets)insets;

このようなものも追加
それで、


UIImage * imageTrimmed = [image imageByTrimmingTransparentPixelsWithMargin:UIEdgeInsetsMake(10, 10, 10, 10)];

こんな感じでトリム出来るようになりました。本家のgithubにもpull requestを送ったのですが、マージしてもらえるでしょうかね?

iOSデベロッパーからのiOS7以降への改善希望する点

「iOS 7」で予想される全面刷新–アップルとJ・アイブ氏がMySpaceから学ぶべき教訓 – CNET Japan
WWDCへ約1ヶ月となりました。iOS7関連の記事も増えてきていますね。現状のiOS, Android (その他OS)のモバイルOSを見ていくと、Androidユーザー、開発者からすると、iOSは遅れているという見方があるのは事実です。確かに、iOSを見て、それにないところを追加しようとしてきたAndroidが、多くの機能を持っているのは事実です。例えば

  • バックグラウンド対応
  • アプリケーション間の連携
  • IMEの自由度
  • アプリが前面にないときに、ウィジェットのように表示が出来る

などは、Androidの優位点として挙げられます。しかし、Androidにも弱点(iOSの優位点)が多くあります。例えば、

などです。簡単にまとめると、”Androidは何でも出来て、iOSはそうでもないけど、iOSは出来る事がサクサク出来る”という感じでしょうか。

しかし、2007年のオリジナルiPhoneに載っていたiPhone OS(1)から基本的に変わっていない、SpringBoard(ホーム画面アプリ) などはその典型と言えます。当時はタッチでアイコンを押して簡単にアプリを起動出来る、先進のものでしたが、やはり改善するとよい点がたくさんあると思います。

最初の記事では、

「iOS 7」がいつ登場するかは分からないが、1つ分かっていることがある。iOS 7がこの数年で最も大規模なiOSの刷新になるということだ。もしかすると過去最大の変更となるかもしれない。

と予想されています。iOSの大きな変更を挙げると、

  1. iPhone OS2でAppStoreに対応し、サードパーティーアプリ開発者コミュニティが形成された – 2008年
  2. iOS4 でマルチタスク、限定的なバックグラウンドに対応 – 2010年

になるでしょう。これらと比べると、その他のメジャーアップデートは小さのものと言えます。

  1. iPhone OS3で対応する機能が増えた – 2009年
  2. iOS5 で、Storyboardなどによる開発効率向上 – 2011年
  3. iOS6 で、AutoLayoutなどにより、デバイスサイズの多様化の準備 – 2012年

僕は個人的にはiOS6でメジャーアップデートが行われると思っていたのですが、比較的内部的な方向だったので、iOS7では、もう少し脱旧世代モバイルOSを計ってもらえればと思っています。記事で述べられているような、デザイン的な変更も興味があります(iOSの将来、”Objectified”という映画 | Zero4Racer PRO Developer’s Blog )が、API的な変更を期待しています。

APIとして追加してほしいのは、ぱっと思い浮かぶのは以下のものでしょうか。

  1. Push Notificationからのバックグラウンド動作
  2. これは欲しいですね。アプリを起動しなくても、アプリ内のSQLiteDBやCoreDataを更新する事によって、実際起動したときにデータを素早く起動したり、Push Notification → バックグラウンド動作 → Local Notification という事も可能になります。アプリが常に待機しなくてもよいので、電池の持ちもそこまで悪くないと思います。

  3. アクティブなアイコン、Notification Center
  4. 現状アプリのアイコンをアクティブに変える事が出来ませんが、カレンダーのアイコンだけは、日付によって数字を変えています。これと同じ事を各アプリが出来れば、タスクの内容を表示したり、注意を喚起したり出来ると思います。また、天気アプリや株価アプリのように動的な Notification Center をアプリが対応出来れば、キラーアプリも増えるでしょう。

  5. アプリケーションから、他のアプリケーションの一部の機能をバックグラウンド呼び出す
  6. これは現在でもある程度は可能ですが、別アプリを呼び出すと最前面のアプリが変わってしまいます。そうではなくて、バックグラウンドで別のアプリを呼び出して、その結果を表示するという事が出来れば、データの処理だけを別のアプリに任せる事も可能になります。

  7. サードパーティーIME、サードパーティーブラウザのデフォルト化
  8. iOSのデフォルトブラウザ、デフォルトIMEはよいものですが、しかしやはり機能の制限はあります。それで、MacがそうであるようにIMEなどのAPIアクセスを可能にし、ATOKのようなIMEをインストール可能にすれば、特に日本ではいろいろなアイディアが出て、iOSとしての進歩にもつながると思います。

  9. 汎用的な外部アプリ呼び出し
  10. 例えば、GoodReaderから、PhotoShopを呼び出して、保存をするとGoodReader側に保存出来るような仕組みが、両方のアプリが対応しなくても、それぞれのアプリがAPIに対応すれば対応出来るような変更が必要になると思います。

  11. Siri, Voice Inputのサポート拡大
  12. Siri, Voiceによる入力は、現状ではアクセシビリティの設定や、ユーザーがキーボードから入力をしたときに限られますが、アプリ側で常にvoiceコマンドを受け入れるモードを対応出来たり、siriが受け取ったコマンドをアプリに送る事が出来たりすれば、フィジカルコンピューティングデバイスとしてのiOSの機能が増えていくと思います。

  13. 下位互換サポート
  14. これはこれまでのアプリがある程度でも動くという事ですが、これまでのiOSもうまくやってきているので問題無いと思います。

まだ何かあった気がしたけど、とりあえずこんなところと思います。ようはiPhoneが最初に発売されたときに、シングルコア400MHz、メモリ128MBくらいでのスタートだったと思いますが、今では、デュアルコア1GHz、メモリ1GBと、ちょっと前のデスクトップくらいのスペックになっている訳です。以前は、モバイルのために色々制限をする事に多くのメリットがあったのですが、モバイルデバイスの使用が多様化したため、電池を消費してもバックグラウンドで使用したいとか、画面を更新したいとかのニーズが増えています。デベロッパーがユーザーのニーズに応えて、工夫してユーザーがびっくりするようなアプリを作る事が出来る環境をiOSが整えてくれるのが、開発者としての一番の願いですね。そうすれば、ユーザーがiOS、またそのなかでのお気に入りアプリを使い、そしてそれを皆に勧めるはずなので、iOS全体の活性化になると思います。

それを見るためにWWDCに行きたかったのですが、今回は色々な状況を見てあきらめました。ただ、チケット争奪戦を見てみたくて、チケット開始のときにログインして、結局チケット買わなかったのですが、どうもチケット確保されていたみたいです。決済しなかったら自動キャンセルになるとの事なので、同じような状況でキャンセル待ちが繰り上がってくれればいいなと願う次第です。。。

CFNetworkを使用したFTP接続のiOS6でのエラーに関して

ちょっと面倒なエラーが出たので備忘として記録しておきます。プロジェクトで使用している自作のFTPクラスでは、CFNetworkで作成したFTPストリームを、NSInputStreamに変換して、FTPの接続を行っています。メインキュー以外から呼ばれる前提で、非同期ではなく、同期的に呼ぶようにしています。

- (void) startGetSynchronous {
self.sema = dispatch_semaphore_create(0);
self.myFTPType = kFTPTypeGet;
CFReadStreamRef ftpStream;

NSInputStream * networkStream;

assert(networkStream == nil); // don't tap receive twice in a row!

ftpStream = CFReadStreamCreateWithFTPURL(NULL, (__bridge CFURLRef) self.ftpURL);
assert(ftpStream != NULL);

networkStream = (__bridge_transfer NSInputStream *) ftpStream;
[networkStream setProperty:(id)kCFBooleanTrue forKey:(id)kCFStreamPropertyFTPUsePassiveMode];

networkStream.delegate = self;
dispatch_async(dispatch_get_main_queue(), ^{
[networkStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[networkStream open];
});

// Have to release ftpStream to balance out the create. self.networkStream
// has retained this for our persistent use.

self.error = nil;
self.dataReceived = [NSMutableData dataWithLength:0];

dispatch_semaphore_wait(self.sema, DISPATCH_TIME_FOREVER);
#if OS_OBJECT_USE_OBJC!=1
dispatch_release(self.sema);
#endif
}

このサンプルは、Appleのsampleに基づいて作っていました。SimpleFTPSample: Document Revision History SimpleFTPSampleでも、依然はこのように、InputStream自体は、retainせずに、RunLoopに追加する事によってオブジェクトが生存する形となっていました。
これで、iOS5でも問題無く動いていました。ただiOS6で基本的に動くのですが、ときどきエラーが起きてFTPが接続出来なくなったりしていました。エラーログを見ると、

Error: request (0x______) other than the current request(0x0) signalled it was complete on connection 0x_______

のようなエラーが出ていました。このメッセージで検索してみると、別のFTPマネージャーでも同じようなエラーが出ている模様。
Error: request (0x989dd00) other than the current request(0x0) signalled it was complete on connection 0x9b8c6e0 · Issue #5 · nkreipke/FTPManager

ここでは、ARC環境においてのメモリ管理が関係しているのではないか、そしてオブジェクトをstrongプロパティにすればよいのではないかという議論が行われていたので、僕の個人のクラスも、NSStreamオブジェクトをクラスのプロパティに変更して見たところ、エラーが発生しないようになっていました。

self.networkStreamInput = CFBridgingRelease(ftpStream);
[self.networkStreamInput setProperty:(id)kCFBooleanTrue forKey:(id)kCFStreamPropertyFTPUsePassiveMode];

self.networkStreamInput.delegate = self;
dispatch_async(dispatch_get_main_queue(), ^{
[self.networkStreamInput scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.networkStreamInput open];
});

SimpleFTPSample自体も、2013/4/12に修正されています。その修正履歴には、SimpleFTPSample: Document Revision History

2013-04-12 Fixed a bug that caused an incompatibility with iOS 6 (r. 13171568), along with other minor changes including (r. 12478239).

となっていて、iOS 6との互換性問題のバグによって修正されたとありますね。最初からクラスのプロパティか、strongのインスタンス変数にしておけばよかったと思いましたが、サンプル通りに作っていたので、サンプルと同じ問題にぶつかっていました。ただ、CFNetworkによるFTPの動作がiOS5以前とiOS6で変更されたというのは事実のようですので、もし使っている方はご注意を。

ちなみに、参考にしたページには僕からもgitHubのissuesページに問題が解決した事を伝え、こちらのクラスもiOS6対応版に修正されたようです。まさに問題を共有して改善していくソーシャルコーディングですね。
Error: request (0x989dd00) other than the current request(0x0) signalled it was complete on connection 0x9b8c6e0 · Issue #5 · nkreipke/FTPManager