property ぷろぱてぃ


@property (nonatomic,copy) NSString* name;

———————
atomic
省略時のデフォルト。synchronizedでスレッドセーフにしたgetter,setterを生成します。

nonatomic
スレッドセーフでない単純なgetter,setterを生成します。iOSではパフォーマンスの問題からほとんどの場合nonatomicにすべきです。

———————

readwrite
デフォルト。getter/setter両方を生成します。


readonly
getterのみ生成します。

———————

geter=メソッド名
getterの名前を設定する。デフォルトはプロパティ名と同じ。BOOL 型のプロパティの名前を is〜とすると分かりやすくなります。

seter=メソッド名
setterの名前を設定する。デフォルトは「setプロパティ名」。あまり使われることはありません。

———————

assign
非オブジェクト型のデフォルト。NSIntegerなど値型、C由来の型など、メモリ管理が必要ないものに使用します。オブジェクト型の場合はassignでなくweakかunsafe_unretainedが推奨されます。

strong
オブジェクト型のARC環境デフォルト。setterで代入前のものをreleaseし、新たに代入するものをretainします。非オブジェクト型には使用できません。

retain
strongと全く同じです(参考:Transitioning to ARC Release Notes)

weak
オブジェクト型の非ARC環境デフォルト。代入時にretain/releaseを行いません。メモリアクセスエラーを避けるため参照先が解放された時はnilになります。strongと同様、非オブジェクト型には使用できません。

unsafe_unretained
weakと似ていますが、releaseされてもnilになりません。assignと同じですが、こちらはオブジェクト型を対象としています。

copy
retain/releaseする点はstrongと同じですが、代入時にsetterで引数のオブジェクトをretainせずに、新たなオブジェクトとしてコピー(_value = [value copy])してからretainします。用途としてはNSStringなどmutableな型(NSMutableString)が子クラスとして存在するものについて、代入後に外部からの値の変更を防ぐためにstrongの代わりにcopyを使用します。

 

Webからファイルを取得して保存

URL指定でファイルを取得したい場合、従来は以下の方法で取得できたが NSURLConnectionは deprecated(非推奨) となった

//取得先のコンテンツのURLを設定
NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/test/mydata.txt"];
];
    
//リクエストを作成
NSURLRequest *req = [NSURLRequest requestWithURL:url];
//レスポンスを作成
NSHTTPURLResponse *res;
NSData *contents = [NSURLConnection sendSynchronousRequest:req returningResponse:&res error:nil];

// ファイルへ書き出す
NSString *path = [NSString stringWithFormat:@"%@/mydata.txt", NSHomeDirectory()];
BOOL ret = [contents writeToFile:path atomically:YES];

NSURLSession dataTaskWithRequest:completionHandler に変更せよとのこと

// NSURLSession を使った方式

//NSURLSessionDataTaskは非同期タイプなので、待ち合わせを行う為に、セマホを使う
// 初期値 0で作成しているので、初回は必ず、待ち状態になる。
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

//リクエストオブジェクトを作成
NSURL *url = [NSURL URLWithString:@"http://uid:password@localhost/test_login_basic/test.txt"];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];


/*
    NSURLSessionConfiguration
    データをアップロードおよびダウンロードするときに使用する動作およびポリシーを定義します。
    データをアップロードまたはダウンロードするときは、常に設定オブジェクトを作成する必要があります。
    このオブジェクトを使用して、タイムアウト値、キャッシュポリシー、接続要件、
    およびNSURLSessionオブジェクトで使用する他の種類の情報を構成します。
    
    ephemeralSessionConfiguration
    エフェメラルセッション構成オブジェクト
    キャッシュ、Cookie、または資格情報に永続ストレージを使用しないセッション構成を返します。
 */
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];


NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];

/*
 dataTaskWithRequest:completionHandler:
 指定されたURL要求オブジェクトに基づいてURLの内容を取得し、完了時にハンドラを呼び出すタスクを作成します。
 このタスクは、応答とデータ配信のためにメソッドを委譲するための呼び出しをバイパスし、
 代わりに結果のNSData、NSURLResponse、およびNSErrorオブジェクトを補完ハンドラ内に提供します。
 ただし、認証の問題を処理する代理メソッドは引き続き呼び出されます。
 引数
 completionHandler
 ロード要求が完了したときに呼び出す完了ハンドラ。
 このハンドラはデリゲートキューで実行されます。
 nilを渡すと、タスクが完了するとセッションデリゲートメソッドだけが呼び出され、
 このメソッドはdataTaskWithRequest:メソッドと同等になります。
 */

NSURLSessionDataTask *task = [session dataTaskWithRequest:urlRequest
                                        completionHandler:^(NSData * _Nullable data,
                                                            NSURLResponse * _Nullable response,
                                                            NSError * _Nullable error)
                              {
                                  
                                  NSLog(@"did finish download.\n%@", response.URL);
                                  
                                  if (error) {
                                      NSLog(@"%@", error);
                                      dispatch_semaphore_signal(semaphore);
                                      return;
                                  }
                                  
                                  NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
                                  if (httpResponse.statusCode != 200) {
                                      dispatch_semaphore_signal(semaphore);
                                      return;
                                  }
                                  
                                  
                                  NSString *path = [NSString stringWithFormat:@"%@/mydata.txt", NSHomeDirectory()];
                                  BOOL ret = [data writeToFile:path atomically:YES];
                                  if ( ret == YES ) {
                                      NSLog(@"ファイルがダウンロードできました");
                                  } else {
                                      NSLog(@"ダウンロードに失敗しました");
                                  }

                                  /*セマホを+1する*/
                                  dispatch_semaphore_signal(semaphore);
                                  
                              }];

/*タスクが中断している場合は、タスクを再開します。*/
[task resume];

/*
    #define DISPATCH_TIME_FOREVER (~0ull)
    セマホが1になるまで待ち合わせをする。永遠に。
 */
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

NSLog(@"compliate");


参考

http://Cat.jp.as.criteo.com

NSURLConnection から NSURLSession への移行例 - Qiita

Blocksを活用する事例と小技 - Qiita

配列 いろいろ

NSArrayからイテレータ的に値を取得

NSArray* bars = arrayWithObjects:bar1,bar2, nil];

NSEnumerator* eratorBar=[ bars objectEnumerator];
    
NSDictionary* aBar;
while (aBar = [eratorBar nextObject]) {
    NSLog(@"%@", [aBar objectForKey:@"key1" ]);
    NSLog(@"%@", [aBar objectForKey:@"key2" ]);
}

 


参考

http://libro.tuyano.com/index3?id=560003&page=6

http://libro.tuyano.com/index3?id=560003&page=6

 

segueを使わないで画面遷移

view1からview2に遷移する場合

ViewController1.m

- (IBAction)btnPage2:(UIButton *)sender {
    UIStoryboard* myStoryboard = self.storyboard;

    ViewController2* viewController2 = [myStoryboard instantiateViewControllerWithIdentifier:@"view2"];

    viewController2.dataString = @"aaa";
    
    [self presentViewController:viewController2 animated:YES completion:nil];
}

 

view2からの戻り遷移

ViewController2.m

- (IBAction)btnBack:(UIButton *)sender {
    [self dismissViewControllerAnimated:YES completion:nil];
}

 

ポイント

ViewControllerのIDは事前に設定しておく必要あり。

ボタンのクリックイベントとメソッドの紐付けは、control+ドラッグで行なっている。

遷移したいタイミングで、遷移が可能なので、segue を使うより感覚的に、わかりやすい。

思ったよりも簡単だった。

UIViewController のライフサイクルについて

UIViewControllerのライフサイクル - Qiita

にすばらしい説明があった

viewDidUnload とかは、以前はあったようが、途中で消滅している

viewDidUnloadがdeprecatedになった理由を考察 | Cyber Passion for iOS

 


参考 

iOS のイベント駆動をライフサイクルイベントとユーザアクションイベントにわけて理解するhttp://glassonion.hatenablog.com/entry/20120405/1333611664

 

Unwind Segueによる画面遷移

戻り遷移の際に、判定を加えたい。

ネットのサンプルを見ると canPerformUnwindSegueAction を使って判定すれば良いように記述されていたが、試して見ると、例外が発生してしまう。

代わりに shouldPerformSegueWithIdentifier でならできた

- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender{
    // NOを返却すると、戻り遷移はしない
    return YES;
}

参考

[Swift]初心者向け!Segueを使った画面遷移方法http://yuu.1000quu.com/how_to_use_segue

 

[Swift]コードで画面遷移を行う3つの方法http://yuu.1000quu.com/screen_transition_in_swift

StoryboardとSegueの基本 - Kesin's diary

UIDocumentInteractionController が iPadで有効にならない

Deployment device が iPhoneだと正常に起動するが、

Deployment device が iPadだと連携先のメニューが表示されない。

なんで?

iPhoneiPadで選択メニューの表示方法が異なる。

 iPhoneの場合は、中央下に表示されるが、iPadの場合は、座標を指定しないとダメみたい。

トリガーのボタンの右下の座標を基準に、選択メニューを表示するようにしてみた。

- (IBAction)btnOpen:(UIButton *)sender {
    [self fileOpen:@"sample.pdf" ui:sender];
}

-(void)fileOpen:(NSString*)fileName ui:(UIButton*)ui {
    NSURL *url = [NSURL fileURLWithPath:fileName];

    CGRect rect = CGRectMake(ui.frame.origin.x + ui.frame.size.width ,ui.frame.origin.y + ui.frame.size.height,0,0);
    isValid =[_docInteractionController
            presentOpenInMenuFromRect:rect
                               inView:self.view
                             animated:YES];
}

 上記のように実装しても、iPhoneでは相変わらず、下中央に開く

 


参考

ios - UIDocumentInteractionController not appearing on iPad but working on iPhone - Stack Overflow