年 2013年

NSDateComponentsからNSDateを取得するとnilが返ってくる

日付値に対して加減演算を行い、その結果を日付値として取得したくてNSDateComponentsクラスを使用した。以下のようなコードを書いたら、 @result@ は常に @nil@ が入って来る。

NSDate* dt = [NSDate date];
NSCalendar* cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents* dc = [cal components:NSYearCalendarUnit fromDate:dt];
// dcに対する操作
NSDate* result = [dc date];

そこでNSCalendarオブジェクトを使って以下のように変更したら期待通りの値が取得できた。

NSDate* dt = [NSDate date];
NSCalendar* cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents* dc = [cal components:NSYearCalendarUnit fromDate:dt];
// dcに対する操作
NSDate* result = [cal dateFromComponents:dc];

 

List File Attributes バージョン1.1.0版公開

ダウンロード

◆ これは何か?

  • ファイルのパス名、サイズ、更新日時などの属性をリスト化するアプリケーションです。
  • とはいっても、ただリスト化するだけでは価値が無くて、それを属性項目ごとにクリップボードへコピーして、他のアプリケーションで利用することを想定しています。
  • 個人利用ではほとんど使う機会はないと思いますが、法人などではファイルを資産として管理する場合、ファイルの一覧を作成することがあると思います。しかし対象のファイル数が多いと、これがなかなか面倒くさい作業で、そういった作業の負荷を軽減するためにこのアプリケーションを作成しました。

◆ 動作環境

.NET Framework 4.0 が動作する環境。

  1. お使いのコンピュータにまだ .NET Framework 4.0 を導入されていない場合は以下のURLからダウンロードしてインストールを行う必要があります。
    https://www.microsoft.com/ja-jp/net/netfx4/download.aspx

◆ 使い方

  • 情報を取得したいファイルまたはそれらを含むフォルダをマウス等でドラッグ&ドロップします。
  • パスに関しては区切り文字の設定や、何文字目からコピーするかを指定します。
  • コピーしたい項目(名前、パス、サイズ、更新日時、作成日時)をプルダウンリストから選び、コピーボタンを押下するとクリップボードにその項目がコピーされます。
  • 一度実行後、続けて作業を行いたい場合は「全てクリア」ボタンを押してリストをクリアしてから、再度ファイルまたはフォルダをドロップして作業を行うことができます。

◆ 利用条件

  • 本ソフトウェアはフリーウェアとして公開しています。ご利用に当たり料金は発生いたしません。
  • 著作権はクロスラボラトリーにあります。

◆ 免責事項

  • 本ソフトウェアは無保証です。ご利用によって生じたいかなる損害に対しても作者は責任を負わないものとします。ご自身の責任においてご利用ください。

更新履歴

  • v1.0.0 (2013-07-07)
    公開
  • v1.1.0 (2013-07-10)
    パスを相対パスと絶対パスに分けて表示・コピーするように修正

Letter Case Converter バージョン1.1.0公開

ダウンロード

◆ これは何か?

  • アルファベットの大文字表記、小文字表記を含めた記法を変換するためのアプリケーションです。
  • 主にソフトウェアの開発者が、項目名や変数を定義する際に、コーディング規約あるいは命名規約等に適合させるために大文字・小文字を揃えたり単語をハイフンやアンダースコアで連結させるといったことを頻繁に行いますが、その作業を支援するために作成しました。
  • 例えば次のような記法に相互に変換ができます。
    1. Upper Camel Case(PascalCaseとも)
      aaa bbb ccc ⇒ AaaBbbCcc
      (例)McDonald, PlayStation
    2. Lower Camel Case
      aaa bbb ccc ⇒ aaaBbbCcc
      (例)iPhone, jQuery, cdmaOne
    3. Start Case
      aaa bbb ccc ⇒ Aaa Bbb Ccc
      (例)App Store, Internet Explorer
    4. Spinal Case
      aaa bbb ccc ⇒ aaa-bbb-ccc
      (例)AIR-EDGE, co-op, e-business
    5. Upper Snake Case
      aaa bbb ccc ⇒ AAA_BBB_CCC
      (使用例)DBのオブジェクト名、プログラムの定数名など
    6. Lower Snake Case
      aaa bbb ccc ⇒ aaa_bbb_ccc
      (使用例)DBのオブジェクト名、プログラムのローカル変数名など

◆ 動作環境

.NET Framework 4.0 が動作する環境。

◆ 使い方

  • 変換元欄にテキストを貼り付けます。
  • 変換元欄に貼り付けたテキストの区切り文字を選びます。
  • 変換後の大文字・小文字の種別と、区切り文字を選びます。
  • 変換ボタンを押すと変換結果欄に変換後のテキストが表示されます。
  • コピーボタンを押すとクリップボードにコピーされます。
  • 大文字・小文字の種別は以下のようになっています。
    1. 全ての単語の先頭が大文字 ⇒ Aaa Bbb Ccc
    2. 2番目以降の単語の先頭が大文字 ⇒ aaa Bbb Ccc
    3. 全て大文字 ⇒ AAA BBB CCC
    4. 全て小文字 ⇒ aaa bbb ccc

◆ 利用条件

  • 本ソフトウェアはフリーウェアとして公開しています。ご利用に当たり料金は発生いたしません。
  • 著作権はクロスラボラトリーにあります。

◆ 免責事項

  • 本ソフトウェアは無保証です。ご利用によって生じたいかなる損害に対しても作者は責任を負わないものとします。ご自身の責任においてご利用ください。

更新履歴

  • v0.0.1 (2013-04-18)
    公開
  • v1.0.0 (2013-05-25)
    アイコンを追加して正式版とする
  • v1.1.0 (2013-07-10)
    連続した区切り文字をスキップするように修正

Master-Detail Appで新規追加画面から戻るとUITableViewに空のセルが追加されてしまう

Xcodeでプロジェクトを作成する時に選べるテンプレートの中に「Master-Detail Application」というのがある。これはいわゆる一覧画面と詳細画面を行き来する割と代表的なアプリケーションの形であり、頻繁に利用されるパターンでもある。一覧と詳細と言えば、その多くがデータベースのようなものと組み合わせて使うのが一般的だ。ローカルのデータベースの場合、特にこだわりがなければCoreDataを使う事になると思うが、その際にちょっとハマったケースがあるのでメモしておく。

それは詳細画面というより編集画面を新規追加の局面で開いた場合だ。ところで「Master-Detail Application」ではUITableViewControllerの他にUINavigationControllerが使われているので、編集画面にて保存の操作を行うにはUINavigationBarに保存ボタンを追加し、NSManagedObjectContextオブジェクトのsaveメソッドを呼ぶ事で保存を行うことができる。ただ、編集画面を新規追加で開いた瞬間にNSManagedObjectクラスのインスタンスが生成されるようで、保存せずに戻るボタンが押された場合には一覧画面に空のセルが追加されてしまう。これを防ぐには戻るタイミングで未保存の変更がある場合には、以下のようにロールバックするコードを書けば良い。

- (void)viewWillDisappear:(BOOL)animated {
    if ([self.managedObjectContext hasChanges]) {
        [self.managedObjectContext rollback];
    }
}

これで空のセルが追加されるのを防ぐ事ができる。

UITextFieldがキーボードに隠れないようにオフセットする

iPhoneでアプリの画面にたくさんTextFieldを配置した時、画面下の方のTextFieldを選択するとキーボードが下からニョキッと出てきてTextFieldを隠してしまう。もちろんそのままでも入力は可能だが、キーボードを仕舞うまでどう入力されているか分からないので不便である。
そこで、TextFieldを選択したときに隠れてしまう場合は表示をずらして隠れないようにしたい。ネットでサンプルを探したのだが、これというものが見当たらなかったので作ってみた。

InterfaceBuilderでまず全体にUIScrollViewを敷き詰めて、そこにUITextFieldを並べていく。

まず、(隠れてしまう)全てのTextFieldについて「Editing Did Begin」と「Editing Did End」の2つのイベントハンドラを定義しておく。この際、どのTextFieldに対しても同じメソッドを適用する。例えばそれぞれ – (void)textEditingDidBegin および - (void)textEditingDidEnd とする。

この時、InterfaceBuilderを使って普通にイベントハンドラを定義しようとすると両方とも「Editing Did End」イベントに結合してしまうので、ConnectionsInspectorで「Editing Did Begin」イベントから – (void)textEditingDidBegin メソッドに結合した方が良い。



また次のフィールドを宣言しておく。

@interface ViewController () {
    float _keyboardOffset; // 表示のオフセット(どれだけずらすか)
    float _offsetMargin; // 実際にオフセットを適用し始めるマージン
}
    :
    :
@end

そしてそれぞれ次のように初期化する。

- (void)viewDidLoad
{
    [super viewDidLoad];
    :
    :
    _keyboardOffset = 0.0f;
    _offsetMargin = 120.0f; // 4インチディスプレイの場合は 210.0f 程度
}

_offsetMargin というのは、例えば画面の上の方にあるTextFieldを選択したときは表示をずらす必要がないので、じゃあY座標がどこまでの範囲内ならオフセットしないかというのを決めておく必要がある。3.5インチの場合はだいたい120ピクセルぐらいまではずらさなくても大丈夫。4インチの場合は3.5インチの場合と90ピクセルくらい差があるのでマージンもそれだけ増やして大丈夫だ。

次に最初に定義したイベントハンドラを実装する。

- (IBAction)textEditingDidBegin:(UITextField *)sender {
    // オフセットすべきサイズを計算する
    CGRect textFieldRect = [sender frame];
    _keyboardOffset = MAX(0, textFieldRect.origin.y - _offsetMargin);
    // アクティブなTextFieldが表示されるようにオフセットする
    CGRect viewFrame = [self.scrollView frame];
    viewFrame.origin.y -= _keyboardOffset;
    self.scrollView.frame = viewFrame;
}

- (IBAction)textEditingDidEnd:(UITextField *)sender {
    // ScrollViewのオフセットを元の値に戻す
    CGRect viewFrame = [self.scrollView frame];
    viewFrame.origin.y += _keyboardOffset;
    self.scrollView.frame = viewFrame;
    _keyboardOffset = 0.0f;
}

尚、UITextFieldDelegateとかオフセット時のアニメーションとかは本題から外れるので適宜実装してください。

UITableViewの一覧にCora Dataで取得した内容を反映する

Core Dataのサンプルとか、UITableViewのサンプルとかはネット上でも書籍でもかなり豊富にあるのだが、それらの組み合わせの例は意外と少ない。先日見つけた書籍はかなり詳しく書いてあって「これはいけるか!?」と思われたが、実は肝心なコードが抜けていた。それはMaster-Detail型で言うところのMaster画面でCore Dataから取得したデータの一覧をUITableViewに表示する際、一覧の見出しにデータの内容が反映されないのだ。おそらくその書籍の著者にとってはあまりに自明の事なので記載するのを忘れてしまったのだろう。あるいはそれくらいは自分で考えろという事なのかもしれない。

まあここで毒づいても仕方が無いので対処方法をメモしておく。

一覧に内容を反映させるには MasterViewController.m の
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
メソッドにコードを記述する。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell;
    // iOSのバージョンによりセルの取得方法が変わる
    if (6.0 <= [[[UIDevice currentDevice] systemVersion] floatValue]) {
        cell = [tableView dequeueReusableCellWithIdentifier:@"AnyId" forIndexPath:indexPath];
        [self configureCell:cell atIndexPath:indexPath];
    }
    else {
        cell = [tableView dequeueReusableCellWithIdentifier:@"AnyId"];
        if (!cell) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"AnyId"];
        }
    }
    // ここでセルの表示を変更
    NSManagedObject* managedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
    cell.textLabel.text = managedObject.anyProperty;
    return cell;
}

 


尚、iOSのOSバージョンを判別する方法は以下のサイトを参考にした。
https://syszr.com/s14.html

“The model used to open the store is incompatible with the one used to create the store” に対処する

Core Dataを使った開発をしていたら次のようなエラーが出てシミュレータで起動しなくなったので、対処方法をメモしておく。

The model used to open the store is incompatible with the one used to create the store

プロジェクトをクリーンしてもダメで、このエラーメッセージで検索したところ、sqliteのファイルを削除しないとダメなのだそうだ。
そのsqliteファイルは以下の場所。ターミナルを開いてrmコマンドで削除する。

/Users/{ユーザー名}/Library/Application Support/iPhone Simulator/{iOSバージョン}/Applications/{英数字}/Documents/{プロジェクト名}.sqlite

参考にしたページはこちら
https://u2k772.blog95.fc2.com/blog-entry-167.html

No iOS Development certificate was found に対処する

iOSでの開発を久しぶりに、しかも新しい機種で行おうとしたらxcodeで「No iOS Development certificate was found」というエラーになり、デバイスが登録できないという現象に陥ったので、対処方法を忘れないようにメモしておく。

単にProvisioning Profileの有効期限切れなのだが、どうやったかすっかり忘れてしまっている。これまた久しぶりに iTunes Connect へアクセスし、「Certificates, Identifiers & Profiles」というメニューに入る。左メニューの「Provisioning Profiles」にて[+]マークをクリックすると新しいプロファイルを作成する手順に移行する。

新しいプロファイルの作成過程で、証明書も期限が切れていると証明書(ios_development.cer)も作り直すことができる。この時別の証明書(CertificateSigningRequest.certSigningRequest)が必要になる。もしこれも有効なものが無ければキーチェーンアクセスから認証局に証明書を要求する。これで無事にプロファイル(*.mobileprovision)が作成され、ダウンロードが可能になる。

最後にxcodeのOrganizerでダウンロードしたプロファイルを追加すればデバイスを登録できるようになる。

UIButtonに任意の画像を使ってタップ時にハイライトさせる

今更ではあるがメモしておく。

画面上にボタンを用意するにはUIButtonを使うが、標準の外観では物足りない場合はボタンに見える画像を用意することが多い。ところがHTMLのつもりでImageプロパティに画像を指定してTitleプロパティにラベルを指定…とやってしまうと画像だけ表示されてラベルが表示されない。

その場合はラベルも含んだボタン画像を用意するというのも一つの方法だが、ボタンの種類が多い場合は用意すべき画像が多くなってしまう。背景画像(BackgroundImageプロパティ)に画像を設定する。

ただ、単純に背景画像を設定してもいいが、より細かく表現するにはボタンの状態別に画像を用意する。非活性状態、有効状態、選択状態、押下状態の4種類あればよいだろう。それぞれ次のようなコードになる。

[button setBackgroundImage:[UIImage ...] forState:UIControlStateDisabled];
[button setBackgroundImage:[UIImage ...] forState:UIControlStateNormal];
[button setBackgroundImage:[UIImage ...] forState:UIControlStateSelected];
[button setBackgroundImage:[UIImage ...] forState:UIControlStateHighlighted];

これを利用してトグルボタンのような機能を持たせることもできる。タッチイベントを捕捉してOFF状態であればONにし、ON状態であればOFFにするという具合だ。しかし、これがうまく動作してくれない。いや、トグルは動作するのだが、OFF状態のボタン押下中のハイライト画像が表示されないのだ。

まず、adjustsImageWhenHighlightedプロパティはfalseにしておこう。これがtrueだとOFF状態のボタンを押下した時にハイライト画像ではなく、ボタン全体が暗転してしまう。だがそれでもまだ不充分。

どうやらUIControlState~はビット和を指定することが可能らしい。つまりON状態とOFF状態だけでなく、OFF状態のボタンを押下中やON状態のボタンを押下中という表現ができる。それを改良したのが次のコード。

[button setBackgroundImage:[UIImage ...] forState:UIControlStateDisabled];
[button setBackgroundImage:[UIImage ...] forState:UIControlStateNormal];
[button setBackgroundImage:[UIImage ...] forState:UIControlStateSelected];
[button setBackgroundImage:[UIImage ...] forState:(UIControlStateHighlighted|UIControlStateNormal)];
[button setBackgroundImage:[UIImage ...] forState:(UIControlStateHighlighted|UIControlStateSelected)];

これでボタンの状態に関係なく、ボタン押下中はハイライト画像を表示させることができた。

“Unknown class ‘class name’ in Interface Builder file” に対処する

久しぶりにiOSアプリの開発環境をいじったら久しぶりにハマったのでメモしておく。

現象としてはXcodeからプロジェクトをビルドしてシミュレータで起動しようとすると、起動できずにアプリは終了し、以下のエラーメッセージを吐くというもの。実際には「class name」には作成したクラス名が入る。

Unknown class ‘class name’ in Interface Builder file

対処方法は次の通り。

  1. XcodeのProject Navigatorでプロジェクトのルートを選択して設定画面を開く。
  2. Standard editorの左ペインで TARGETS 以下の項目を選択する。
  3. Standard editorの右ペインの Build Phases タブを選択する。
  4. Compile Sources のグループを開き、不足しているクラスのソース本体(.m)を追加する。
  5. ビルド及び実行する。

これはInterface Builderから特定のクラスが見えないという状況なのだが、例えば新規にプロジェクトを作成した時に、他のプロジェクトで作成したクラスをファイルのコピーによって追加したような場合に発生する。(クラスを新規作成で追加した場合は自動でBuild Phaseに追加されるようだ。)