iPadをMacBookProのサブディスプレイにするアプリを比較してみた
元Appleの社員さんが作ったというDuetDisplayの登場で、なんだかこの界隈が盛り上がっている様子。そこで、これまで買って試してきたものも含めて3つのアプリを比較してみたいと思います。
公式動画もありますが、せっかくなのでもうちょっと変わったことに挑戦してみました。iPad含めた3画面で比較!!
メインマシン:
MacBookPro Retina 13inch (Late 2013)
画面は最適(Retina)の1280 X 800にしています。
セカンドディスプレイ:
iiyama ProLite E2410HDS
24型のFull HD(1920 x 1080)をHDMIで接続しました。
iPad(第3世代):
Retina (2048 x 1536)ですが、以下の動画では1024 x 768で表示しています。
接続ケーブルは30ピンです。
■Duet Display
ふれこみ通りの滑らかさ。3画面であっても問題なしです。
マウスの移動などの操作では、ほんのちょっとラグを感じます。
Duet Display側の画面解像度を変更することはできませんが、Retinaの補完をして画像を滑らかにするモードはあります。ただし、これにすると動画はもたついてしまいますので、通常はRegularで使うのが良いかと思います。
■TwomonUSB
同じくUSBでつないでサブディスプレイ化するアプリです。
正式対応をしているのはWindowsなのですが、OSX用のα版が公開されています。
http://easynlight.com/twomonusb/다운로드/
あくまでα版での動作ということで。
このアプリでは3画面共有ができませんでした。(メインとセカンドディスプレイ、セカンドディスプレイとiPadなど、いずれかがミラーリングになってしまう)
また、画面を認識した時点で、メインマシン側も動画がもたつき始めました。
なお、接続したiPadの解像度を細かく変えることができました。
■DisplayPad
最後はWi-Fiで共有するDisplayPadです。
こちらは3画面での描画が可能でした。
やはり動画はキツイです。カクカクして、まとまって動いたりします。静止画も回線状態によってはもたつきが発生します。
こちらも解像度を自由に選べました。 さらに、DisplayMenuという、ツールバー常駐の解像度変更アプリからも選択が可能です。
■総評
やはり、速度などの面でDuetDisplayが飛び抜けています。
ただ、値段も一番高いので利用頻度次第ですかね。
iPad でサブディスプレイというのを体験してみたい!という場合は、一番安価なDisplayPadが手軽でいいかと思います。TwomonUSBは、費用を抑えつつも安定したい場合でしょうか。
それぞれのアプリの今後のアップデート次第ですが、2014年暮れでは確実にDuetDisplayがオススメです!
プログラマーなら読んどけ!な本を、電子書籍で読みたい!!
最近よく「プログラムするなら読んどけ!」の本の紹介がされてる気がします。
ちまちま自分の範囲でやってる自分としては、そういった知識が(も)乏しいので、そういった本を読んでみたいと思っております。
プログラムなどの技術系の本って、分厚いのが多い。ちょっとでもかさばらず読みやすい方法・・・となると、これこそ電子書籍の出番かなと。
ということで、電子書籍で買えるプログラム関連の本を探してみました。なおKindleとBookLive!がありますが、BookLive!はたまに20%オフセールなどをやってるのでその時を狙うのがいいのかなと思います。
まずは、たいてい最初に書かれていることが多いのが、この本でした。
これだけで上下合わせて1200ページを超えるボリューム!!EPUBなので、文字サイズ変更できますね。
続いて、開発手法な本。
BookLive!版 BookLive!版はナシ
「アジャイル開発とスクラム」は、アジャイル?スクラム?なにそれ??という状態で読み始めるにもいいなーという本で、「アジャイルなゲーム開発」は、いわゆるWebサービスとは違うプロジェクトに使う場合に役立ちそうな内容でした。
「ドメイン駆動設計」「アジャイルサムライ」は、見つけたぞ&読んでみよう!な本です。
swift出てきたけど、iPhoneをいじってるのでやっぱりこちら。
本棚に並べてムフフと眺めるのも一興なのですが、総勢3000ページ以上の本たちをiPadなどに潜ませて持ち運んじゃうのも、なかなかのものですよね。
秋の夜長に。
はてなブログの自分の記事を、いろんな言語に翻訳してみたい!
Google翻訳ツールを使ってみる。タグを埋め込むだけで、いろんな言語に翻訳するボタンが追加されると言うけど、本当かなあ?
・・・ほんとだった!
Googleアカウントでログインしてここにアクセス。
https://translate.google.com/manager/website/suggestions
変更したい言語を選んで表示方法も決めます。
最後のページで出てくるコードのうち、「ページ上にウェブサイト翻訳ツール プラグインを表示する位置にこのスニペットを配置してください」の方をコピーして、はてなブログの記事を「HTML編集」で開いて、記事の一番下にペーストします。すると、この記事のように下に翻訳ボタンが出ましたー。
※もし記事の編集中に翻訳ボタンが意図しない位置で表示されるようになってしまったら、同じくHTML編集を開いて、「<div id="google_translate_element"></div>」がどこに挿入されているかをチェックします。この場所にボタンが表示されるっぽげ。
UITextViewで自動保存とかやってみたい!
いまどきのアプリなら、やっぱりいちいち「保存」ボタンとか押さない。勝手に保存しちゃうはず。ましてや3.5インチのフロッピーをアイコンにしないはず!
ということで、ひとまずフォーカスを失うごとに内容を保存させるメモ。カスタムにつくったTableViewのCellでハマったのでそこを重点的に。
基本はDelegate
手順としてはこんな感じ。
1:ViewにUITextViewを配置
StoryBoardでぱっと。Viewのクラスにアウトレットを繋いでおきます。
2:Viewの.hでDelegateを宣言
<UITextViewDelegate>を忘れずに。
3:Delegateを設定
.mの中でUITextViewのdelegate = selfを書いちゃう。
4:イベントをとる
「UITextViewの編集終わり」ということで、こちらを指定。
-(void)textViewDidEndEditing:(UITextView *)textView
ここで、テキストの値をCoreDataなりParseなりに保存します。
普通(?)ならこれでOKなんですが、同じ心づもりで自作したCellのTableViewでやったら、なぜかイベントが取れない!?delegateに指定もされてるはずなのに・・・。
で、よくよく見たところ、ワタクシ、
- initWithStyle:style reuseIdentifier:reuseIdentifier
の中でdelegate=selfしてました。これを
- awakeFromNib
の中に変更したところ、無事にイベントがとれました。
忘れていつかまたやりそう。
ParseのCloud Codeでsaveとかしたい!
簡単お手軽にアプリのサーバサイドを担当してくれるParse.com。単に保存するだけならアプリから適当にデータを投げるだけなのですが、「いいね!の数をカウントアップする」みたいな、クライアント側でがんばるよりもサーバでうまいことやってもらった方が良い処理もあったりします。
そんなことを可能にするのがCloudCodeらしい・・・。
ということで、自分なりに調べてみた結果をメモ。
参考にしたのは、こちらの公式ページです。
toolのインストール
大好きなGUIはなく、基本的にコマンドラインでカタカタやるしかないようです。
まずはターミナルを起動して次のコマンドを使ってtool一式をインストール。
Macの場合
curl -s https://www.parse.com/downloads/cloud_code/installer.sh | sudo /bin/bash
このときPasswordを聞かれますが、これはマシンにインストールしようとしてるので管理者のパスワードですね。 Installing....とか出たあと終わります。
セットアップ
引き続き、次のように打ち込む。「MyCloudCode」というのはParse.comで設定しているAppに対応したCloudCodeの作業をするディレクトリの名前として使われます。なので、もしAppを登録していなければ先にParse.comのサイトで作っておいた方が良いです。
$ parse new MyCloudCode
ユーザーのディレクトリの中に、このMyCloudCodeというディレクトリが作られます。(中に3つのディレクトリ&3つのファイルも)
ディレクトリなどを作り終わったら、EmailとPasswordを聞かれます。これはParse.comのを入れます。ログインできたら、自分が登録しているアプリの一覧が表示されます。今回のCloudCodeに紐づけたいアプリを選択すると終了です。
ごっそり作られたディレクトリとファイルですが、configは触らなくてOK。publicは静的コンテンツをアップする場所らしく、実際にコードを書くのはcloud以下にあるmain.jsだそうです。なお、文字コードはUTF-8がよさげ。
実行タイミングについて
いくつかイベントが設定されてるぽい。どのタイミングで実行させるかによって、書き方が異なります。それぞれの名前は、アプリから叩くときの名前として使われます。
そのコードを叩かれた時に実行
いわゆる普通のやつ。
Parse.Cloud.define(“名前”, function(request, response){
}
Parseのデータが変更された時に実行
アプリからParseのデータを操作すると、それを感知して実行されるらしい。
セーブ前に呼び出される
Parse.Cloud.beforeSave(“名前”, function(request, response){
}
セーブ後に呼び出される
Parse.Cloud.afterSave(“名前”, function(request){
}
削除前に呼び出される
Parse.Cloud.beforeDelete(“名前”, function(request, response){
}
削除後に呼び出される
Parse.Cloud.afterDelete(“名前”, function(request){
}
バックグラウンドで実行
時間がかかる処理など。
Parse.Cloud.job("名前", function(request, status){
}
書き方
結局はParseをJavaScriptで読み書きするのでここの文法に沿って書けば良いのだけど、自分がよく使う内容だけ抜粋。memberというClass(いわゆるテーブル)にname、ageというCol(いわゆるフィールド)がある体。
Classesの指定
var query = new Parse.Query("member");
リクエストについた引数の取得
アプリから投げるときにnameという名前でTaroとか送ってきたというイメージ。変数にはTaroがはいります。
var targetName = request.params.name;
クエリーに抽出条件を設定
たとえばこんな感じで。
query.equalTo("name",targetName);
query.greaterThan("age",18);
抽出
成功失敗それぞれの処理を書いておく。抽出できたとき、結果はfunctionの( )の中に書いた変数へ納められる。複数あるときはそれが配列になっていて、result[i]とかで取り出せる。
query.find(
success: function(results){
// 成功時の処理 resultsに結果が入っている
},
error: function(error){
// 失敗時の処理 error.codeでエラーコードが拾える
}
);
値の取得、書き換え
上の例のresultsが配列で、それの1つめを操作する場合。
取り出す
var tmpName = results[0].get("name");
書き換える
results[0].set("name","Jiro");
インクリメント
results[0].increment("age");
値の保存
これも成功と失敗の処理を用意しておく。
results[0].save({
success: function(){
// 成功時の処理
},
error: function(error){
// 失敗時の処理
}
});
レスポンスを返す
ここでは文字列を固定で返してますが、もちろん計算結果や抽出結果など返してOK。
成功時
response.success("成功!");
失敗時
response.error("失敗・・・");
スクリプトのアップロード
これまたコマンドです。
$ parse deploy
実行
とりあえずターミナルから確認するにはこんな感じ。URLは「実行するタイミング」のところで書いた名前を記述。
curl -X POST \
-H "X-Parse-Application-Id: {Application ID}" \
-H "X-Parse-REST-API-Key: {REST API Key}" \
-H "Content-Type: application/json" \
-d '{}' \
{ }の中身はそれぞれみんな違っていて、簡単に参照するには
にアクセスして、値を参照するのが手っ取り早げ。
「ParseをJavaScriptで操作するようにかけばいいんだった!」と気がつくのに、少々時間がかかりました・・・。
次はテストに挑戦したい。
MagicalRecordで保存したつもりが、アプリ再起動すると消える!?
完全にハマりました。お手上げ気味でした。
起きていた症状はこんな感じ。
・MagicalRecordを使ってるiOSアプリ
・MagicalRecordを使ってデータを保存する
・アプリが起動している間は、読み書き自由
・アプリを再起動すると、保存できていたはずのレコードが消えてる
・他の箇所では、同様の方法でも正常に保持されてる
原因を端的に言うと、「この処理だけ別スレッドで実行してた」というものです。データを保存する際、NSManagedObjectContextを指定して保存しますが、それを何も考えず
context = [NSManagedObjectContext defaultContext];
とやってました。defaultContextを指定すればええんでしょ?てなもんです。
これを
context = [NSManagedObjectContext contextForCurrentThread];
としたところ、無事に再起動後も保存完了!
もちろん、狙いがあって別のスレッドで明確に分ける場合はそれぞれでNSManagedObjectContextを指定する必要があると思いますが、まとめたいのに分かれちゃった場合は要注意ですね。そもそもこの組み方いいの??っていう問題もありそうですので。
あぶないところでした。
iPhoneでポップアップをカスタマイズしたい!
iPhoneでいわゆる普通のポップアップを表示するならUIAlertViewを使えば良いのですが、ポップアップしたviewにいろいろしようと思うとちょっと大変。
そこで見つけたのがMJPopupViewControllerというもの。
martinjuhasz/MJPopupViewController · GitHub
使い方は簡単だったものの、なんか忘れそうなのでメモ。
1:MJPopupViewControllerを追加
zipでダウンロードしたら、Sourceフォルダの中にある4ファイルをプロジェクトに追加します。
- MJPopupBackgroundView.h
- MJPopupBackgroundView.m
- UIViewController+MJPopupViewController.h
- UIViewController+MJPopupViewController.m
CocoaPodsで入れるならここか。
MJPopupViewController for iOS - Cocoa Controls
2:ポップアップ用のクラスを作る
MJPopupViewControllerは通常のUIViewを表示するので、UIViewControllerのサブクラスとして作成します。
3:ポップアップ用のxibを作る
新規xibを作ってここにViewを配置します。縦横サイズがデフォルトでは画面いっぱいになりますが、変更するにはViewを選んでここ!
そして忘れないようにFile's Ownerを選択してCustomClassを設定します。
さらに、File's Ownerのviewと配置したViewのOutletを繋ぐのを忘れずに。
4:呼び出しもとで準備
MJPopupViewControllerと1で作ったクラスをインポート。
#import "UIViewController+MJPopupViewController.h"
#import "PopupViewController.h"
5:ポップアップを実行!
1で作ったクラスのインスタンスを用意して、MJPopupViewControllerを使って表示します。
PopupViewController *popUpView = [[PopupViewController alloc]initWithNibName:@"(Xibの名前)" bundle:nil];
[self presentPopupViewController:popUpView animationType:MJPopupViewAnimationFade];
animationTypeのところは、いろいろな指定があるのでサンプルを見ながら使い分けましょう。
このままであれば、ポップアップ以外の場所をタップすることで閉じます。ポップアップ上に配置したボタンを使って閉じる場合は、1のクラスにdelegateを付けて、呼び出しもとがメソッドを実装して
[self dismissPopupViewControllerWithanimationType:MJPopupViewAnimationFade];
などとしてあげることで消すことができました。
現場で通用する力を身につける iPhoneアプリ開発の教科書 【iOS 7&Xcode 5対応】
- 作者: 森巧尚,まつむらまきお
- 出版社/メーカー: マイナビ
- 発売日: 2014/01/25
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (3件) を見る