タグ別アーカイブ: objective-c

objective-c関連

Objective-cにおけるプロパティとはなんだ?

プロパティとインスタンス変数の違いが良くわからなかったので調べてみた。

インスタンス変数

インスタンス変数はそのクラスから生成されたインスタンスオブジェクトが生きている限りは保持されるインスタンス固有の変数。

プロパティはそのインスタンス変数にアクセス指定子を付けて宣言することで、インスタンス自身ではないオブジェクトからもアクセスできるようになる。

インスタンス変数にはアクセス指定子を付けてアクセスを制御できる。

  • @private
  • @protected
  • @public //デフォルト
  • 例:@private uint age;

->でインスタンス変数にアクセスできる。
ただしアクセス指定子をつけても警告のみでアクセスできてしまうし、ビルドも通る…。ェ…。

Objective-Cにおけるプロパティはどんな機能を持っているのか?

* アクセサメソッドが自動的に作られる

Objective-Cのプロパティを実装するにはどうしたらいいか?

.hファイル側で

  • @property(retain) NSString* propertyName;
#import

@interface PropertyCheck : NSObject

@property (retain) NSString* name;

@end

.mファイル側で

  • 通常はこう記述する。
    • @synthesize propertyName;
  • インスタンス変数名とプロパティ名が違う場合は以下の様にする。(※インスタンス変数が”_propertyName”の場合)
    • @synthesize propertyName = _propertyName;
#import "PropertyCheck.h"

@implementation PropertyCheck{
//  NSString* name;
}

- (id)init{
  self = [super init];
  self.name = @"default";
  return self;
}

@synthesize name;

@end

ただし!

  • @dynamic propertyName で宣言するとアクセサメソッドは生成されない。
  • @dynamic propertyName で宣言するとコンパイル時にチェックされない。エラー、ワーニング等がでない。

生成されたアクセサメソッドの構文はドット表記で行うが良い。

  PropertyCheck* propChck = [[[PropertyCheck alloc]init]autorelease];
  NSLog(@"prop.name = %@",propChck.name);
  propChck.name = @"iPhone3GS";
  NSString* name = propChck.name;
  NSLog(@"name      = %@",name);
  NSLog(@"prop.name = %@",propChck.name);
  propChck.name = @"iPhone4S";
  name = propChck.name;
  NSLog(@"name      = %@",name);

これでログ側には

 prop.name = default
 name      = iPhone3GS
 prop.name = iPhone3GS
 name      = iPhone4S

と表示されるはず。

ドット演算子の利点

通常の表記だとコンパイル時にチェックされないので実行するまでメソッド名が正しいかとか、存在するか等がわからない。
しかしドット演算子を使用すると使用可否がコンパイル時にチェックされる。

アクセサメソッドに任意の名前を付ける

アクセサメソッド名を自作するには以下の様に表記を変更する。
@property (getter=nowHealthPoint, setter=damagedHealthPoint:) NSInt enabled;
getterは引数無しだがsetterは引数ありなので必ずセミコロンを記述しておく。
同じ変数にアクセスするのでgetterの返り値の型とsetterの引数の型は一致する。この例ではNSIntにしてある。

プロパティの属性

  • readwrite
    • 読み書き可だよ。
  • readonly
    • 読み込みのみだよ。setterが生成されなくなる。
  • retain
    • 新規参照。参照数をインクリメント。
    • ガービッジコレクションを有効にしてるとretainは無効になる。
    • ガービッジコレクションを無効にしている場合、手動でreleaseする必要がある。
  • assign
    • まま渡される。
    • ガービッジコレクションが無効だと警告の上、これが適用される。
  • copy
    • set時にコピーが渡される。
    • ガービッジコレクションを無効にしている場合、手動でreleaseする必要がある。

プロパティとインスタンス変数

インスタンス変数として宣言するならプロパティとして定義した方が良いという結論に。
歴史ある言語って色々便利な分だけ分かりにくいね…。等など。

参考

iOSプログラミング逆引きリファレンス108 ~知りたいことがすぐわかるiPhoneプログラミングテクニック~

iPhoneプログラミングUIKit詳解リファレンス

iOSデバッグ&最適化技法 for iPad/iPhone
詳解 Objective-C 2.0 第3版

パブリッククラスとコンクリートクラスとクラスクラスタと

コンクリートクラスとかクラスクラスタとか聞き慣れない単語がでてきたので、漠然と理解するよりもちゃんと解説されてるものを読んで理解しておこうと思い調べたのでメモ。

コンクリートクラスって?

コンクリートクラスとは、”有名どころのクラス”のサブクラスで、”有名どころのクラス”を使用しておけば、格納するデータに応じて最適なクラスを自動的に割り当てるObjective-cの機能で呼び出されたクラス。

クラスクラスタって?

クラスクラスタとは、”有名どころのクラス”とそのサブクラス全体を含めたクラス群のこと。

具体的にどういうものかをソースを書いて理解

  NSString* str = [[NSString alloc]initWithString:@"/path/path/"];
  NSLog(@"str = %@",[str class]);

コンソールには…

2011-12-12 13:41:24.295 playground[13697:f803] str class = __NSCFConstantString

だとさ。

つまり、ユーザが宣言したクラスではなく、そのクラスを継承したサブクラスが自動で割り当てられてて、

ってあれ?パス用のクラスクラスタが割り当てられると思っていたのだけれども?

…。

そうそう、これをさっきのコードに追加してみると…

  NSString* path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
  path = [path stringByAppendingPathComponent:[NSStringstringWithFormat:@"%d.txt",str]];
  NSLog(@"path class = %@",[path class]);

こんなレスポンス

2011-12-12 13:41:24.295 playground[13697:f803] str class = __NSCFConstantString
2011-12-12 13:41:24.296 playground[13697:f803] path class = NSPathStore2

となる。

両方ともNSStringで宣言してるのにClassが違う。
ここで実際に表示されたクラス群がコンクリートクラス。
親になってるスーパークラスはNSStringはパブリッククラスと呼ばれる。
なのでNSStringクラスで使用可能なクラスメソッド/インスタンスメソッドは継承してるコンクリートクラスでも使える。

stringByAppendingFormat:メソッドを実行するとNSPathStore2クラスに変換されたりするのかな?という思いつき。
※stringByAppendingFormat:メソッドがNSPathStore2クラスに付属するメソッドなのかどうかは調べてません。

最後にこれを追加してみる。

  str = [str stringByAppendingFormat:@"file.txt"];
  NSLog(@"str = %@",str);
  NSLog(@"str class = %@",[str class]);

コンソールには

2011-12-12 13:41:24.295 playground[13697:f803] str class = __NSCFConstantString
2011-12-12 13:41:24.296 playground[13697:f803] path class = NSPathStore2
2011-12-12 13:52:22.455 playground[13873:f803] str = /path/path/file.txt
2011-12-12 13:52:22.456 playground[13873:f803] str class = __NSCFString

最初にチェックしたstrのクラスは”__NSCFConstantString”だったのが”__NSCFString”になってる。
データをstringByAppendingFormat:メソッドによって生成したオブジェクトなので格納されてるデータが変わったのかな?と仮説を立ててみた。

色々試した結果、どうやら格納されるデータをどのように生成したかによって割り当てられるクラスが変動するみたい。

  NSString* str2 = [@"test" stringByAppendingPathComponent:@"/path/path/"];
  NSLog(@"str class = %@",[str2 class]);

このコードだと、最初に宣言されたstr2は NSStringのstringByAppendingPathComponent:メソッドによって生成されているので、クラスはPathStore2な!と言われて割り当てられた感じ。

2011-12-12 14:12:31.654 playground[14265:f803] str2 class = NSPathStore2

宣言はNSStringで行っているのでメモリサイズもそれに準じたフィールドが宛てられていると推測。なのにクラスが変わっててもいいの?とかとか疑問は湧く、が追い過ぎ注意。
間違っていたら改めるとして、生成時に副次的に生じる情報を元に判別している、とだけ解釈するまでにここでは留めておこう。

図にしてみる

話を戻してコンクリートクラスとパブリッククラスを図にするとこんな感じ。

クラスクラスタ

まとめ

プログラマが宣言するクラスがパブリッククラス。
実際に割り当てられるクラスがコンクリートクラス。
それらを全部合わせてクラスクラスタ。

また一つ、賢くなってしまった…。

参考

Format string is not a string literal

警告!な写真
NSLogの引数にNSStringのメッセージ文を直接書いていたらなぜかワーニング“Format string is not a string literal”が出て気持ち悪いので調べてみたらあっさり。

NSLog([NSString stringWithFormat:@"Milk"]);

これだとWarningがでます。

調べたら…

グーグル先生に訪ねたらこんな回答が。
http://stackoverflow.com/questions/5428325/issue-with-code-format-string-is-not-a-string-literal


NSLog(@"%@",[NSString stringWithFormat:@"%@", entered]);

教えてくれた人曰く、セキュリティを破る事に成りかねないYOとの事。

内容があまりにも簡単過ぎるからだとは思うのだけど、日本後でこういったエラーメッセージに対応してる記事をあまりみない。英語力が解決力に通じてると実感。

【objective-c】 setKeyboardType一覧


setKeyboardTypeで指定する定数がいっぱいあったので一覧化。
違いがわかったりわからなかったり。

iOSでテキスト入力箇所をアクティブにした際に呼ばれるキーボードの指定一覧

指定

サンプル
UIKeyboardAppearanceDefault

UIKeyboardTypeDefault1
UIKeyboardTypeDefault2

UIKeyboardTypeTwitter

UIKeyboardTypeTwitter1UIKeyboardTypeTwitter2

UIKeyboardTypeAlphabet

UIKeyboardTypeAlphabet

UIKeyboardTypeEmailAddress

UIKeyboardTypeEmailAddress1
UIKeyboardTypeEmailAddress2

UIKeyboardTypePhonePad

UIKeyboardTypePhonePad

UIKeyboardTypeNumberPad

UIKeyboardTypeNumberPad

UIKeyboardTypeURL

UIKeyboardTypeURL1UIKeyboardTypeURL2

UIKeyboardTypeNumbersAndPunctuation

UIKeyboardTypeNumbersAndPunctuation1UIKeyboardTypeNumbersAndPunctuation2

UIKeyboardTypeASCIICapable

UIKeyboardTypeASCIICapable

UIKeyboardTypeDefault

UIKeyboardTypeDefault1UIKeyboardTypeDefault2

おまけ

テキストエリア生成コードサンプル

objective-c:
-(UITextField*)makeTextField:(CGRect)rect text:(NSString*)text type:(NSInteger*)type{
    //テキストフィールドを生成し、rect,text,色,キーボードに関する情報をセットして返す。
    UITextField* textField = [[[UITextField alloc] init] autorelease];
    [textField setFrame:rect];
    [textField setBackgroundColor:[UIColor whiteColor]];
    [textField setBorderStyle:UITextBorderStyleRoundedRect];
    //以下がキーボード関連。キーボードのアピアランス、キーボードの種別、改行キーの種別
    [textField setKeyboardAppearance:UIKeyboardAppearanceDefault];
    switch((NSInteger)type){
        case 1:
            [textField setKeyboardType:UIKeyboardTypeDefault];
            [textField setText:@"UIKeyboardTypeDefault"];
            break;
        case 2:
            [textField setKeyboardType:UIKeyboardTypeASCIICapable];
            [textField setText:@"UIKeyboardTypeASCIICapable"];
            break;
        case 3:
            [textField setKeyboardType:UIKeyboardTypeNumbersAndPunctuation];
            [textField setText:@"UIKeyboardTypeNumbersAndPunctuation"];
            break;
        case 4:
            [textField setKeyboardType:UIKeyboardTypeURL];
            [textField setText:@"UIKeyboardTypeURL"];
            break;
        case 5:
            [textField setKeyboardType:UIKeyboardTypeNumberPad];
            [textField setText:@"UIKeyboardTypeNumberPad"];
            break;
        case 6:
            [textField setKeyboardType:UIKeyboardTypePhonePad];
            [textField setText:@"UIKeyboardTypePhonePad"];
            break;
        case 7:
            [textField setKeyboardType:UIKeyboardTypeEmailAddress];
            [textField setText:@"UIKeyboardTypeEmailAddress"];
            break;
        case 8:
            [textField setKeyboardType:UIKeyboardTypeAlphabet];
            [textField setText:@"UIKeyboardTypeAlphabet"];
            break;
        case 9:
            [textField setKeyboardType:UIKeyboardTypeTwitter];
            [textField setText:@"UIKeyboardTypeTwitter"];
            break;
        default:
            break;

    }
    [textField setReturnKeyType:UIReturnKeyDone];
    return textField;
}

iOSプログラミング逆引きリファレンス108 ~知りたいことがすぐわかるiPhoneプログラミングテクニック~

iPhoneプログラミングUIKit詳解リファレンス

iOSデバッグ&最適化技法 for iPad/iPhone
詳解 Objective-C 2.0 第3版