2015年2月2日月曜日

[iOS][Objective-C]文字列の各種変換


どうも。

文字列の各種変換。
全角→半角とか、
ひらがな→カタカナとか、
ローマ字→ひらがなとか。

普段あんまり必要としない機能というか、
ついぞ最近になってやりたいシーンが出てきて、
調べてみたら...。

NSStringには該当するメソッドはありませんが、
CFMutableStringに行き着きました。
で、CFStringTransform関数というのを使えばいいみたい。
定義を覗いてみると。

[CFStringTransform関数]

CF_EXPORT
Boolean CFStringTransform(CFMutableStringRef string, CFRange *range, CFStringRef transform, Boolean reverse);

[transform]

/* Transform identifiers for CFStringTransform()
*/
CF_EXPORT const CFStringRef kCFStringTransformStripCombiningMarks;
CF_EXPORT const CFStringRef kCFStringTransformToLatin;
CF_EXPORT const CFStringRef kCFStringTransformFullwidthHalfwidth;
CF_EXPORT const CFStringRef kCFStringTransformLatinKatakana;
CF_EXPORT const CFStringRef kCFStringTransformLatinHiragana;
CF_EXPORT const CFStringRef kCFStringTransformHiraganaKatakana;
CF_EXPORT const CFStringRef kCFStringTransformMandarinLatin;
CF_EXPORT const CFStringRef kCFStringTransformLatinHangul;
CF_EXPORT const CFStringRef kCFStringTransformLatinArabic;
CF_EXPORT const CFStringRef kCFStringTransformLatinHebrew;
CF_EXPORT const CFStringRef kCFStringTransformLatinThai;
CF_EXPORT const CFStringRef kCFStringTransformLatinCyrillic;
CF_EXPORT const CFStringRef kCFStringTransformLatinGreek;
CF_EXPORT const CFStringRef kCFStringTransformToXMLHex;
CF_EXPORT const CFStringRef kCFStringTransformToUnicodeName;
CF_EXPORT const CFStringRef kCFStringTransformStripDiacritics CF_AVAILABLE(10_5, 2_0);

CFStringTransform関数に対して、
定義されたtransformを指定してやると、
そのように変換してくれる。

再利用性と、
CFのコードをなるべく書かなくていいように、
必要そうな分をピックアップしてNSStringのカテゴリにしてみた。

[NSString+ConvertLetters.h]

@interface NSString (ConvertLetters)

- (NSString *)convertToFullwidth;
- (NSString *)convertToHalfwidth;
- (NSString *)convertKatakanaToHiragana;
- (NSString *)convertHiraganaToKatakana;
- (NSString *)convertHiraganaToRoman;
- (NSString *)convertRomanToHiragana;
- (NSString *)convertKatakanaToRoman;
- (NSString *)convertRomanToKatakana;

@end

[NSString+ConvertLetters.m]

- (NSString *)transformWith:(CFStringRef)transform reverse:(Boolean)reverse {
 
    NSMutableString* retStr = [[NSMutableString alloc] initWithString:self];
    CFStringTransform((__bridge CFMutableStringRef)retStr, NULL, transform, reverse);
 
    return retStr;
}

- (NSString *)convertToFullwidth {
 
    return [self transformWith:kCFStringTransformFullwidthHalfwidth
                       reverse:true];
}







みたいな感じ。


それでは。
ちゃお☆


まこぴー。

2015年1月31日土曜日

[iOS][Objective-C]Xcode6でPCHファイルが...


どうも。
ご無沙汰しています。

というか、
もう1月も終わろうとしていますが、
2015年の初投稿ですw

あけましておめでとうございます!

実は、
というか、
もっと早く気付けという話なんですが...。

Xcode6で新規プロジェクトを作成した場合、
(ProjectName)-Prefix.pchが自動では作成されません...。

仕事では既存アプリへの機能追加や不具合修正、
個人的な取り組みでは、
Objective-Cでは既存コードを使った実験、
Swiftなら新規プロジェクトの作成、
みたいな感じでやっていたので、
いざObjective-Cで新規に作ってみて気づいたワケですw

仕方ないので、
xxx.pchファイルを作成して、
[Build Setting]
[Apple LLVM6 6.0 - Language] - [PrefixHeader]に、
$(SRCROOT)/$(PRODUCT_NAME)/xxx.pch
と設定すれば使えるようになります。


それでは。
ちゃお☆


まこぴー。

2014年12月6日土曜日

[iOS][Objective-C]エラー内容のローカライズ表示(NSError)


どうも。

frameworkなどを使って機能を実装する際、
結果をデリゲートによる通知で受けることが多々あります。
成功したら成功した旨のデリゲート、
失敗したら失敗した旨のデリゲート、
といった具合に。

例えば、
失敗したときにエラーのAlertViewを表示してユーザに通知するとする。
他言語対応のアプリだと、Localizable.stringsに項目を増やさなければなりません。
何カ国語も対応している場合には大変です...。

実例として、
日・英・韓・中(繁体字/簡体字)
と対応しているアプリを開発しています。
文言が新たに追加されると、
その分依頼を出さないとどうにもならない状況です。
開発側としても翻訳側としてもその手間をどう省くか?

例えば、失敗のデリゲートでNSErrorが連携される場合、
無条件にエラー内容を出せばよいのなら、
下記の様にすることで、
ローカライズされたエラー内容を取得することが出来る。

NSString *alertMsg = [error localizedDescription];

さらに細かな条件によりメッセージを出し分けたり、
デリゲートで受け取るNSErrorの文言ではフィットしない等あれば、
自力でローカライズするしかないです。

指定5カ国語以外は英語、
みたいな取り決めがある等の場合にも、
自力でローカライズするしかない。

でもこの場合にも、
framework側が出す確認のAlertや部品って、
ユーザ言語に合わせて出てくるから、
frameworkの流れの中では合わせちゃってもいいかな、
と個人的には思います。


それでは。
ちゃお☆


まこぴー。

2014年10月22日水曜日

[iOS][Objective-C]NSDateの比較


どうも。

NSDate同士の比較。
これまで機会がありそうでなかったので、
どうやるんだろうかと...。

もうObjective-Cに関わって何年にもなって、
Swiftも出てきたというのに、
こういうことがちょいちょいありますw

ググれば即出てきますが、
こんなカンジです。

 
    NSDate *date1;
    NSDate *date2;

         (中略)

    NSComparisonResult result = [date compare:date2];
 
    switch (result) {
        case NSOrderedSame:
            // date1 == date2
            break;
        case NSOrderedAscending:
            // date1 < date2
            break;
        case NSOrderedDescending:
            // date1 > date2
            break;
    }


NSComparisonResultはNSNumberの比較でも使いますね。
NSNumberの比較というのも、
個人的にあまりしたことがありませんが...。

NSDateはNSDateFormatter使って、
文字列から生成することもあります。
元になる文字列が、
・フォーマット違反
・日付として無効な数値
になっているなどの場合はnilが返ってきます。
まぁ、ここまでは合点がいきます。

問題なのは、
その後のcompareです。
nilとのcompareは、
NSOrderedSameが返ってきてしまう...。

文字列が信用できるならいいんですが、
今回は文字列が人の手による入力で、
しかも事前にはチェックすらできない状況だったりします。

仕方ないので、
ある程度泥くさいチェックを書かなきゃいけませんね...。

それでは。
ちゃお☆

まこぴー。

2014年10月16日木曜日

[iOS][Objective-C]NSStringからの変換とチェック


どうも。

ひさびさにiOSというか、
Objective-C...。

Swiftの覚え書きはまだもうちょっと先になりそう。
まだまだ仕事ではObjective-Cが現役なんでw

今回は、NSStringです。
NSStringからintやBOOLに変換できます。
plistに設定値を書いといて、
読み出してプログラム内で使うときなんかに重宝します。

NSString *aStr = @"123";
int a = [aStr intValue];
とすると、
aには123が代入されます。

NSString *bStr = @"YES";
BOOL b = [bStr boolValue];
とすると、
bにはYESが代入されます。

まぁ、
当たり前の話ですw
当たり前に使っているが、
実は仕組みを詳しく知らなかったりする。

まずはint変換から。
数値でない文字列の場合どうなる?
Javaで同じようなことをするときは、
NumberFormatExceptionで受けたりしますが、
そういう作法が存在しない以上、
何かしらよしなに値を返してくれるはずです。

NSString *aStr = @"aaa";
int a = [aStr intValue];
とすると、
aには0が代入されます。

@"aaa" → 0
@"123aaa" → 123
@"aaa123" →  0
@"123aa4" → 123

なるほど、
数値文字で始まっていれば、
それが続く限りは数値として認識してくれるみたい。
@"123aaa"を許容しないような場合には、
自力でチェックが必要になります。

チェックについては、
ConvertCheckというカテゴリにして実装してみた。

[NSString+ConvertCheck.m]

- (BOOL)canBeConvertedToInt {
 
    return [self isEqualToString:
            [NSString stringWithFormat:@"%d", [self intValue]]];
}

他にもNSScannerとかNSCharacterSetや正規表現も使えますが、
先に文字列チェックしてしまうとintの範囲を超えたりを気にしたりしなかったり、
コードもちょっと複雑になるんで...。

あと、
これだと@"0000"や@"000009"みたいなのは変換不可になってしまいます。
今回書いたコードの用途上はそれを弾いちゃっていいので構いませんが、
その辺は仕様や実情に合わせたコードを書く必要があろうかと思います。

さて、
今度はBOOL変換。

試してみる前に、
NSString.hを覗いてみると、
こんなコメントがあります。
/*
Skips initial space characters (whitespaceSet), or optional -/+ sign followed by zeroes.
Returns YES on encountering one of "Y", "y", "T", "t", or a digit 1-9. 
It ignores any trailing characters.
*/

つまり、
@"Yeah"でもYESですw
まぁ、
BOOLに関しては、
厳密なチェックが必要なケースってほとんどないと思うんで、
チェックするメソッドも実装しません。
なるほどねーっていうだけですw


それでは。
ちゃお☆


まこぴー。

2014年9月28日日曜日

[Android]Androidアプリのエントリポイント


どうも。

いろいろと忙しく、
久々の覚え書き。

Androidも関わる機会が多くなってきたので、
今回はAndroidに関するトピック。

自分でゼロから作ったり、
最初から全容を把握しているアプリならいいんですが、
もう出来上がったものに対して、
改修や不具合対応などをせねばならない場合もある。
で、
大体の場合ドキュメントはない...。
諸般の事情で、
内部の詳しいつくりを把握している人もいない...。

こんなときには、
与えられたソースコード一式の解析からスタートせねばならない。

で、自分の場合はAndroidアプリに関しては、
大した実戦経験がないワケで...。

しょんぼりしていても仕方ないし、
Androidアプリに限らず、
こんな状態のスタートはよくあることだったりする。

MainActivityとかTopActivityなどと、
クラス名などからアタリがつく場合もあれば、
必ずしもそうでない場合や、
規模が大きい場合など、
まずは困ったときには(アプリの)エントリポイントを探るのが手っ取り早い。

ということで、
Androidアプリのエントリポイントはというと、

AndroidManifest.xmlのintent-filter要素に、
android.intent.action.MAINが設定されているもの

という探し方ができるようだ。
ただし、
android.intent.action.MAIN
は複数のアクティビティに設定でき、
そんな場合には、
android.intent.category.LAUNCHER
が設定されているもの
ということらしい。

すなわち、

<intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

となっているようなActivityを見つければよいことになる。


それでは。
ちゃお☆


まこぴー。

2014年7月18日金曜日

[iOS][Android]iOSアプリ開発からのAndroidアプリ開発


どうも。

ご無沙汰しています。

仕事ではObjective-CでiOSアプリ開発して、
業務外では少しずつSwiftも弄ったりして、
もう一度原点回帰でC++辺りも学び直したいな、
などと、
平和に過ごしていたのですが、
いきなり仕事でAndroidやることに…。
突然なのはラブストーリーだけでじゅうぶんです。

このAndroidやる経緯を書き出すと、
文句だらけになってしまうのでw

とにかく、
望むか望まざるかに関わらず、
俺はAndroidをやらなければならなくなった。
ほとんど実践経験なしです。

iOSとAndroidで同時に開発してたプロジェクトのときに、
画面を含めた仕様を共通で自分が握ってたのと、
何かの折にコードレビューした程度。

iOSアプリの開発してると、
Android開発やってた人が、
突如iOSのエンジニアに仕立てられるというのをよく見てきたが…。
まさか自分がその逆をやらされるとはw

とにかく、
iOSアプリのエンジニアが、
最短でAndroidのエンジニアになる為にどうしたらいいか?

優秀なエンジニアは何でもすぐにできますが、
自分は並以下なんで…。

Androidは基本的にはJavaで書くことになる。
数年前に1年ちょっとくらいJavaの案件に携わる機会があったくらい。
(ほとんど上流工程しかやってないから、実践的な実装経験はかなり乏しい)
とりあえず、Javaがどんなもんだったか思い出す為に、
「AndroidエンジニアのためのモダンJava」
という本を買ってみた。
http://www.amazon.co.jp/Android%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E3%83%A2%E3%83%80%E3%83%B3Java-%E5%B1%B1%E7%94%B0-%E7%A5%A5%E5%AF%9B/dp/477415878X

あっさりした内容だが、
今回の用途には適している気がする。
分かりきってるところはチラ見もしくはぶっ飛ばしてw
(半分以上が不要なんだけどね…w)
個人的にはコレクションについてとマルチスレッドについては、
多少しっかりと。

ネット上で目的に適ったページを探してみた。
事細かく説明してくれるワケではないが、
下記のページが非常に参考になる。

http://developer.smartnews.be/blog/2013/09/06/ios-android/

http://akisute.com/2014/01/ios-android.html

ここまでで、
Hello, world!
くらいのレベルはちゃきちゃきクリア。

ちなみに、
iOSとAndroidを組み合わせた検索をすると、
クロスプラットフォーム的なトピックばかりで、
なかなか今回の用途にフィットした情報は見つからない。
(根気強さと検索テクニックに欠けるのかも…)

後は、
アプリ開発的に重要と思われる事項を概念レベルで確認。
・アクティビティ
・サービス
・インテント
・UI部品(どんなのが標準であるか?のレベル)

ここまでサラリとやっておくと、
何となくキャッチアップできた(気がする)

あとは、
Javaでのシングルトンの実現方法と、
グローバル変数の扱い方の確認。
こいつらは乱用あるいは使用事態を原則的に避けねばならないが、
いざというときに強力な助けになる!

グローバル変数はJavaには概念上存在しないが、
抜け道はあります。
一般にバッドノウハウとして嫌われがちで、
Javaの世界では恐らくその傾向はより顕著でしょうが、
数画面程度のアプリでは使った方が、
解決としてシンプルな場合もあります。

と、
限られた時間(合計して数時間)で、
上記のような整理をして、
なんとかかんとか、
とりあえずは仕事としては進めてる感じですw

あとはやりながら身について、
ノウハウが蓄積されていくと思います…。
もちろん、
継続的に学習は必要かと思いますが。

ということで、
Androidに関しても、
覚え書きしておきたいことは、
整理も含めてここに書く。
と思います。


それでは。
ちゃお☆


まこぴー。