ThumbFan Keyboard 1.0.1がリリースされました。
今回のアプリでの変更点を見ながら、iOSキーボードやiOS8開発の技術についてまとめておきたいと思います。
投稿者: Tomohisa
片手親指でキータイプができる英語キーボードThumbFan Keyboardをリリース。技術概要など
iOS8でエクステンションの機能が追加されて何か作ってみたかったのと、iPhone 6 Plusの大きさによる不便さを解決したいという理由で、片手親指キーボードをつくってみました。
趣味のカメラマンが結婚式カメラマンをするための準備(2)基本の機材
趣味のカメラマンが結婚式カメラマンをするための準備(1)カメラとレンズ | Zero4Racer PRO Developer’s Blog の続編です。ちょっと撮影に行くだけだったら使いたいレンズいくつかとスピードライトを持っていけばよいのですが、結婚式となったら、一日中カメラを使うのでSDメモリ、バッテリーにも気をつけないと行けません。
メモリ、バッテリー
これらは基本ですね。D90で使えるSDHCカードを16GB、32GBのものを買いました。
“趣味のカメラマンが結婚式カメラマンをするための準備(2)基本の機材” の続きを読む
趣味のカメラマンが結婚式カメラマンをするための準備(1)カメラとレンズ
結婚式と言えばやっぱりよい写真が欲しいですよね。僕はプロカメラマンではなくて趣味でカメラを撮っています。数年前にフリーランスの仕事があまり忙しくないときにアメリカで子どものポートレートをとったり、卒業記念のポートレートをとったり、ファミリーポートレートをとったりしていました。先立つものも限られているので、機材も限られたものです。最近はもっぱら家族の写真くらいしかとっていなかったのですが、友人から結婚式のカメラマンをしてほしいとの依頼を受けました。プロのようには行かないことは了承してもらったのですが、手作り結婚式なので、出来る限りでよいのでとってほしいということで、ちょっと久しぶりにカメラ周りをいろいろ勉強して、準備しているところです。喜ばれるよい写真が撮れればいいな。
主に子どものポートレートがメインで、簡易スタジオを作って撮ってました。
アメリカではこのようなコラージュ写真を作って大きくプリント(11×14インチ B4くらい)するのが喜ばれます。
事前の手持ち機材
これらの写真を撮るのに使っていたレンズとカメラはこちら。
“趣味のカメラマンが結婚式カメラマンをするための準備(1)カメラとレンズ” の続きを読む
Objective-Cで、サブクラスだけで使用出来るプロパティを作成する
Objective-Cでクラスを作る場合は、他のクラスからアクセスさせたくないプロパティはクラスエクステンションにして、自クラスだけでアクセス出来るようにします。こんな感じです。
モジュールはこんな感じです。
こうすることによって、notesというプロパティは、参照するクラスからは変更されたくないので、ヘッダーにはreadonly,クラスエクステンションでは、readwriteで定義することによって、クラス内で変更可能です。
booksというプロパティは、クラス内ではNSMutableArrayとして振る舞いたいけれども、対外的には変更してほしくないので、NSArrayとして返しています。booksと別のbooksInternalという内部用プロパティをNSMutableArrayで定義して、内部ではbooksInternalにアクセスすることによって、オブジェクトの追加が出来るようにしています。
このクラスを継承したクラスを作った場合は、対外的には同じくbooks, notesを触られたくないですが、継承したクラス内では触りたい訳です。
モジュールでbooks, notesを触ろうとすると当然ですが、エラーになります。
これを解決するために、クラスエクステンションを別ファイルに出してあげると解決出来ました。
このようにします。
クラスエクステンションの新しいファイルに、プロパティを記述
ベースクラスでは、クラスエクステンションをモジュールでImportします。
継承したクラスでもクラスエクステンションをモジュールでImportします。booksに関しては、内部的にmutableのプロパティ booksInteranlをクラスエクステンションで定義しているのでそちらを使用します。
これで、他のクラスからはprivateExtentionのヘッダーをインポートしないようにすれば定義が見えないので、コンパイル時点で正しい処理が行われていることを確認出来ます。
libextobjc の @ keypath でObjective-Cのプロパティ名を文字列化する
まえから、型チェックをした上でプロパティ名を文字列化したいと思っていました。
@interface MyClass
@property (nonatomic, strong) NSString * myPropertyName;
@end
@implementation MyClass
-(void) myFunc {
self.myPropertyName = @"abc";
NSString * property = NSStringFromSelector(@selector(myPropertyName));
// myPropertyName が出力される
NSLog(@"%@", property);
// abc が出力される
NSLog(@"%@",[self valueForKey:property]);
}
@end
これだと、SEL型から名前をえることが出来るのですが、myPropertyNameというプロパティが、MyClassのプロパティという保証がないので、困ることがあります。valueForKey:で使用した時に間違った方で使用してしまうこともあります。それを解決する方法をまえから考えていたのですが思い浮かばなかったものの、ReactiveCocoa(ReactiveCocoa/ReactiveCocoa )使っていたら、Libextobjc(jspahrsummers/libextobjc )にそれっぽいものがあったので調べてみました。libextobjc は、Objective-Cを便利に使う機能をまとめた関数群で、マクロなどを駆使して欲しい機能が実装されています。libextobjcの、”Compile-time checking of selectors”にはこのように説明されています。
Compile-time checking of selectors to ensure that an object declares a given selector, using EXTSelectorChecking.
セレクタの型チェックをコンパイル時に行うことが出来る、いい感じですね。これで上を書き換えるとこうなります。
@interface MyClass
@property (nonatomic, strong) NSString * myPropertyName;
@end
@implementation MyClass
-(void) myFunc {
self.myPropertyName = @"abc";
NSString * property = @keypath(self.myPropertyName);
// myPropertyName が出力される
NSLog(@"%@", property);
// abc が出力される
NSLog(@"%@",[self valueForKey:property]);
}
@end
分かりやすいですね!ここで、”self.myPropertyName”と書いているので、どのインスタンスの型のプロパティかがコンパイル時にチェック出来ます。RestKitやMantleなどのO/Rマッピング機能を使うために、文字列型でプロパティ名が欲しいことが多いのでとても役立ちます。
どうやっているのかを見て見たところこんな感じでした。
/**
* \@keypath allows compile-time verification of key paths. Given a real object
* receiver and key path:
*
* @code
NSString *UTF8StringPath = @keypath(str.lowercaseString.UTF8String);
// => @"lowercaseString.UTF8String"
NSString *versionPath = @keypath(NSObject, version);
// => @"version"
NSString *lowercaseStringPath = @keypath(NSString.new, lowercaseString);
// => @"lowercaseString"
* @endcode
*
* ... the macro returns an \c NSString containing all but the first path
* component or argument (e.g., @"lowercaseString.UTF8String", @"version").
*
* In addition to simply creating a key path, this macro ensures that the key
* path is valid at compile-time (causing a syntax error if not), and supports
* refactoring, such that changing the name of the property will also update any
* uses of \@keypath.
*/
#define keypath(...) \
metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__))(keypath1(__VA_ARGS__))(keypath2(__VA_ARGS__))
#define keypath1(PATH) \
(((void)(NO && ((void)PATH, NO)), strchr(# PATH, '.') + 1))
#define keypath2(OBJ, PATH) \
(((void)(NO && ((void)OBJ.PATH, NO)), # PATH))
分かりにくいですが、keypath1のところだけを見てみると、
#define keypath1(PATH) \
(((void)(NO && ((void)PATH, NO)), strchr(# PATH, '.') + 1))
こんな感じで、左の、”(NO && ((void)PATH, NO))”でコンパイルチェックだけを通して、実際にはNO &&の後なので使用されないようにしています。
後半の右側で、パラメータを#defineマクロの機能で、文字列化して(# PATH)、その”.”の右側をとったC文字列を作成して、”myPropertyName”となるのですが、keypath( の前に@を付けているので、Objective-C文字列になるという訳ですね。
言葉で説明すると分かりにくいですが、使うと便利と思います。
#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はこういう勉強会で軽く見ながら実践投入する段階で一気に勉強するのが良さそう。いかに公開してくださったスライドのリンクを置いておきます。
uounɹɐʇ (tarunon)さん
NSUserDefaults噺
くろねこまいける (kuronekomichael)さんの発表もそれぞれ良かった。スライドが上がったら追記します。
[Objective-C] libextobjc の @weakify と @strongify について
ちょっと遅れた話題ですが、libextobjcライブラリを使用して、weak変数を使う方法があることを知ったので調査してみました。
これまでの記述法と問題点
これまでわたしは、この記事ARC+Blocks+llvm4.0時代のコード記述作法 | Zero4Racer PRO Developer’s Blog で書いたルールにしたがって、ivar(クラス内の変数)を基本的に使わず、block内で使用する場合に、weak化して使用する方法を使ってきました。WEAKSELFMAKE;というマクロを作成して、selfのマクロを作成しています。
#define WEAKSELFMAKE __weak typeof(self) wself = self
使用する時は、
{
WEAKSELFMAKE;
SomeViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:NSStringFromClass([SomeViewController class])];
controller.block_completed = ^ (NSNumber * toReturn) {
wself.numberValue = toReturn.copy;
[wself redlowItems];
}
}
のような感じです。これで結構シンプルに書けてほぼ問題がないのですが、スコープ内のstrongの変数を使う場合は、weak化を自分で行う必要がありました。ちなみにStoryBoardIDをクラス名にしてNSStringFromClass([SomeViewController class])で書くのが最近のお気に入りです。
{
WEAKSELFMAKE;
SomeViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:NSStringFromClass([SomeViewController class])];
__weak typeof(controller) wcontroller = controller;
controller.block_completed = ^ (NSNumber * toReturn) {
wself.numberValue = toReturn.copy;
[wself redlowItems];
[wcontroller dismissViewControllerAnimated:YES completion:NULL];
}
}
@weakify, @strongifyで出来ること
jspahrsummers/libextobjc は、Objective-Cを便利にする拡張機能ライブラリです。cocoapodで、
pod 'libextobjc', '~> 0.4'
を追加すれば簡単に追加出来ます。上のサンプルを書き直すと、
{
SomeViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:NSStringFromClass([SomeViewController class])];
@weakify(self);
@weakify(controller);
controller.block_completed = ^ (NSNumber * toReturn) {
@strongify(self);
@strongify(controller);
self.numberValue = toReturn.copy;
[self redlowItems];
[controller dismissViewControllerAnimated:YES completion:NULL];
}
}
こんな感じになります。self, controller というオリジナルと同じ変数名を使える代わりに、使う前に、@strongify(self)をしてあげないといけないのがポイントです。
動作原理
Objective-Cのコードに慣れていたらこれが若干気持ち悪いコードに見えます。selfだと循環参照になってしまう気がしてしまうからです。reactive cocoa – Explanation of how weakify and strongify work in ReactiveCocoa – Stack Overflow この記事には、マクロを展開した後のコードが載せられていて分かりやすいです。
これを見ると、@weakifyマクロで self_weak_ というweak変数を作って、@strongifyマクロでself=self_weak_;と新しいself変数を作成していることが分かります。同じ変数名(self)だったら、ローカルスコープのselfの方が優先されるため、selfを使っても循環参照しないんですね。
あと、@weakifyという、予約語を作っているように見えますが、これも強引で、後ろに autorelease (このスクリーンキャプチャの場合は try {} @finally{} 付けることによって、展開後に@autorelease という形になるようにして、無理矢理@予約語のように見せてるんですね。マクロでこんな強引なことが出来るんですね。これの残念なのは、Xcode上での予約された@propertyのようなものと実際には違うので、コード上の色がおかしくなることです。
まとめ
実際これをプロジェクト規約に取り込むかですが、若干微妙なところですね。@strongifyを忘れるとselfを使っているところで循環参照してしまうのと、2行使ってしまうのでコードが煩雑になるので、現在のWEAKSELFMAKE;マクロの方が綺麗な気もします。それで、展開したマクロのself_weak_を使ってあげれば綺麗になると思いました。
{
SomeViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:NSStringFromClass([SomeViewController class])];
@weakify(self);
@weakify(controller);
controller.block_completed = ^ (NSNumber * toReturn) {
self_weak_.numberValue = toReturn.copy;
[self_weak_ redlowItems];
[controller_weak_ dismissViewControllerAnimated:YES completion:NULL];
}
}
これで、@strongifyを書き忘れることもないですし、selfを内部で使っていた時に色で見分けるのも簡単になります。しばらくこれで使ってみようと思います。
参考
cocoapods – libextobjc
libextobjc/extobjc at master · jspahrsummers/libextobjc
Safx: libextobjcの@strongifyと@weakifyについて
Objective-C – weakify/strongify マクロを使うと weak self パターンが簡単に書ける – Qiita
CocoaPodsのプロジェクトで、ヘッダーファイルが読め込めない時の対処方法
1つのプロジェクトに複数のターゲットを作成している時に起きる問題のようで引っかかったのでメモ。
cocoaPodsを導入して、podsで導入したフレームワークのヘッダーファイルが読めずに、
19:9: fatal error: ‘RestKit/RestKit.h’ file not found
のようなエラーが出ました。
“CocoaPodsのプロジェクトで、ヘッダーファイルが読め込めない時の対処方法” の続きを読む
Macの空き容量を増やすために行った8つの整理整頓テクニック
年度末前でいろいろ忙しくなる前に、時間を取ってMacの整理を行いました。なんかいろいろばたばたしていてブログを書くのも久しぶりです。いつもMacの残り容量が40ー60GBで、しばらくほっとくと20GBを切ったりしているので、それは困るなと思って、整理整頓をしました。
“Macの空き容量を増やすために行った8つの整理整頓テクニック” の続きを読む