[Objective-C] なんかあとで使えそうなメモ


## 自身を内包しているビューコントローラを探す

```objc
- (UIViewController *)findViewController
	id nextResponder = self.nextResponder;

	while (YES) {
		if ([nextResponder isKindOfClass:UIViewController.class]) {
			return nextResponder;
		}
		else if ([nextResponder isKindOfClass:UIView.class]) {
			nextResponder = ((UIView*)nextResponder).nextResponder;
			continue;
		}
		else {
			break;
		}
	}

	return nil;
}
```


## Cでオーバーロードを実装する

`__attribute__`ディレクティブを使います。

```overload.h
CGFloat __attribute__((overloadable)) add(CGFloat a, CGFloat b);
```

`__attribute__((overloadable))`とすることでオーバーロードを定義できる。


## ObjCで`super`の呼び出しを必須にする

以下のように`__attribute__`を指定します。

```objc
- (void)hoge:(NSString *)name __attribute__((objc_requires_super));
```

## 標準キーボードの上にカスタムのViewを追加する`inputAccessoryView`

太字にしたり、とか独自のボタンなんかを配置したい場合のやつ。

```objc
UIView *inputAccessoryView = [[UIView alloc] initWithFrame:anyRect];
UITextView *aTextView = [[UITextView alloc] init];

aTextView.inputAccessoryView = inputAccessoryView;
```


## `UIContentSizeCategoryDidChangeNotification`

Dynamic Type使用時の、テキストサイズの変更通知を受け取る。

## `window`を得る

```objc
// viewのプロパティから得る
self.view.window;
```

```objc
// UIApplicationの`keyWindow`経由で得る
[[UIApplication sharedApplication] keyWindow];
```

```objc
// keyWindowで意図しないwindowが取得されるケースもあるらしいので、その場合はこれ

UIWindow *window = nil;
id<UIApplicationDelegate> appDelegate = [[UIApplication sharedApplication] delegate];

if ([appDelegate respondsToSelector:@selector(window)]) {
	window = appDelegate.window;
}
else {
	window = [UIApplication sharedApplication] keyWindow];
}
```

## 可変引数のメソッドを実装する

Objecitve-Cによる可変引数の実装。
可変引数メソッドの宣言には2種類あります。

### パターン1

```objc
- (void)hogeMethod:(NSString *)firstArg, …;
```

`…`の部分が可変引数を表します。

### パターン2（nil終端リスト）

```objc
- (void)hogeMethod:(NSString *)firstArg, …NS_REQUIRES_NIL_TERMINATION;
```

`NS_REQUIRES_NIL_TERMINATION`を指定することで、nil終端リストとして定義できます。

### 実装

実装時、可変引数は以下のように取り出します。

```objc
- (void)hogeMethod:(NSString *)firstArg, …
{
	va_list args;
	va_start(args, firstArg);

	for (NSString *arg = firstArg; arg != nil; arg = va_arg(args, NSString *)) {
		//do use arg.
	}

	va_end(args);
}
```

C言語の関数を利用して処理を行います。

* **va_list**  
可変引数へのポインタを保持する変数。
* **va_start**  
va_listポインタ変数の開始位置を指定します。
* **va_arg**  
va_listから次の引数を取得します。取得の際は引数の型を指定します。（第2引数に型を指定します）
* **va_end**  
va_listで保持されたメモリを開放します。

#### 解説
`va_list`はポインタを保持する変数です。
`va_start`関数の第一引数に渡し、第二引数では可変引数ポインタの、可変開始位置の「ひとつ前の」アドレスを渡します。
こうすることによって、`va_list`型の変数には、可変引数配列の開始位置が格納されます。

次に、`va_arg`関数をひとつ実行するごとにアドレスを移動していきます。アドレス位置を移動していくために、第二引数に取り出す値の型を渡す必要があるのです。（つまり、第二引数分、アドレス位置を進める）

処理が終了したら`va_end`関数で、利用していたメモリを解放して終わります。


### 参考記事
[Objective-Cで可変引数](http://tea-leaves.co.jp/home/ja/article/1365947182)

--------------------------

## 外部からObjecitive-Cのメソッドを叩く

主にWebViewを利用してなにかする場合。
基本的には`webView:shouldStartLoadWithRequest:navigationType`メソッドでリンクをクリックしたときなどの瞬間を補足して、独自のschemeをキーにしてごにょごにょすると思う。

セキュリティうんぬんは置いておいて、とりあえずJSとかからObjective-Cのメソッドを実行するメモ。

```objc
SEL anyMethodName = NSSelectorFromString(@"methodName");
if ([self respondsToSelector:anyMethodName]) {
	[self performSelector:anyMethodName];
	//引数を伴う場合は以下
	[self performSelector:anyMethodName withObject:anyObject];
}
```

`respondsToSelector:`メソッドで実装を確認し、`performSelector:`メソッドで実行。
ただ、これを書くと問題なくても警告が出てしまうので、以下のようにすると警告が出なくなる。（これがいいかは分かりません・・）

```objc
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[self performSelector:anyMethodName];
#pragma clang diagnostic pop
```

[参考記事](http://qiita.com/hal_sk/items/3f983b8270eae479a979)

--------------------------

## ScrollViewのスクロール関連

AutoLayout, Adjust Scroll View Insetsが反映されるタイミングは
`UIViewController#viewDidLayoutSubviews`後。

UIScrollView#contentInsets = {64, 0, 0, 0}
UIScrollView#contentOffset = {0, -64}
これを見るに、contentOffstはスクロール位置かな？

ちなみに設定は以下のようにする。

```objc
scrollView.contentInset = UIEdgeInsetsMake(50.0, 30.0, 40.0, 0);

//現在位置を表すインジケータの位置調整
scrollView.scrollIndicatorInsets = UIEdgeInsetsMake(50.0, 30.0, 40.0);
```

iOS7から、`UIViewController`に、`topLayoutGuide`、`bottomLayoutGuide`プロパティが追加。
topLayoutGuideには`64`という数字が入っているみたい。つまり、バーの高さとかを自前で計算しなくてもいいってことかも。
※`topLayoutGuide`も`viewDidLayoutSubview`デリゲートメソッドが呼ばれるタイミングでを参照しないとレイアウト前で値が入っていない（`0`）ので注意が必要。

--------------------------

## UIViewのZ値

`addSubiew:`と`insertSubView:aboveSubview:` or `insertSubView:belowSubview:`メソッドでSubviewを追加できる。それぞれZ値の値が変わる。

また、`exchangeSubviewAtIndex:withSubviewAtIndex:`メソッドで入れ替えることもできる。

--------------------------

## iOS7のAutoAdjustの有効/無効
UIViewController#automaticallyAdjustScrollViewInsets


当然、iOS6以前ではこのプロパティはないので、これを判別に使って、iOS6以前の場合は`0(+ NavigationBar)`、あったら上記を使う、とするとスマートかも。

--------------------------

## WebViewのコンテンツの表示調整

WebViewの表示領域に対して、コンテンツの拡大を調整する方法。

```objc
UIWebView *anyWebView = [[UIWebView alloc] init];
anyWebView.scalesPageToFit = YES;
```

--------------------------

## status bar上のインジケータの表示

```objc
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES; //or NO
```

--------------------------

## UIToolbar内のレイアウト

UIToolbar内のレイアウトで、センタリングとかどうするのかなーと思ったら、`UIBarButtonItem`の種類に、`UIBarButtonSystemItemFlexibleSpace`と`UIBarButtonSystemItemFixedSpace`というものがあった。
`UIBarButtonItem`をセンタリングしたい場合は、左右に`UIBarButtonSystemItemFlexibleSpace`を配置するとセンタリングされる。

--------------------------

## UIViewなどに含まれる文字列がぴったりはいるサイズを調べる

タイトルなど文字列を設定後、以下のメソッドで設定や取得が可能。

### 文字列ぴったりになるように自動的にフィットする

```objc
[anyLabel sizeToFit];
```

### 文字列がぴったり入るサイズを取得する

```objc
CGSize maxSize = self.view.bounds.size;
CGSize size    = [anyLabel sizeThatFits:maxSize];
```

--------------------------

## あとあと使うかもしれない記事リンク集

* [iOSでのCGContextDrawImage()を最適化する](http://wowdev.jp/?p=988#more-988)