NSHashTableでDelegatesパターン
-
Upload
masaki-oshikawa -
Category
Technology
-
view
472 -
download
3
Transcript of NSHashTableでDelegatesパターン
NSHashTableでDelegatesパターン
自己紹介
@starfruits_j (Little Gleam)
株式会社 Azione
株式会社 Azione のiOSアプリ開発、管理職
昨年末にSQLを書くことが嫌いということでNyaruDBと
Realmについて発表しました
PHPではlaravelがお気に入り
開発実績デコメーラー
Nator
モバスペブック
© 2014 Azione Co.,Ltd. All Right Reserved.
個人でもアプリ出してますQRコードリーダー
FF10 モンスター捕獲数カウンター
hackadl
WebPage翻訳 for Safari
発表内容Swift!?
NSHashTable
使い道について
Objective-Cが好きnilをスキップできるところ
weak参照(ARC)があるところ
メソッド名が長いところ
NSHashTableという存在
使い方NSHashTable * hashTable = [[NSHashTable alloc] init];[hashTable addObject:@"test"];[hashTable addObject:@"obj"];[hashTable removeObject:@"obj"];NSLog(@"table: %@", [hashTable allObjects]);
NSArrayというよりNSSetを拡張したような感じ
ユニークなコレクション
optionsenum { // default is strong NSPointerFunctionsStrongMemory NS_ENUM_AVAILABLE(10_5, 6_0) = (0UL << 0), NSPointerFunctionsOpaqueMemory NS_ENUM_AVAILABLE(10_5, 6_0) = (2UL << 0), NSPointerFunctionsMallocMemory NS_ENUM_AVAILABLE(10_5, 6_0) = (3UL << 0), NSPointerFunctionsMachVirtualMemory NS_ENUM_AVAILABLE(10_5, 6_0) = (4UL << 0), NSPointerFunctionsWeakMemory NS_ENUM_AVAILABLE(10_8, 6_0) = (5UL << 0),
NSPointerFunctionsObjectPersonality NS_ENUM_AVAILABLE(10_5, 6_0) = (0UL << 8), NSPointerFunctionsOpaquePersonality NS_ENUM_AVAILABLE(10_5, 6_0) = (1UL << 8), NSPointerFunctionsObjectPointerPersonality NS_ENUM_AVAILABLE(10_5, 6_0) = (2UL << 8), NSPointerFunctionsCStringPersonality NS_ENUM_AVAILABLE(10_5, 6_0) = (3UL << 8), NSPointerFunctionsStructPersonality NS_ENUM_AVAILABLE(10_5, 6_0) = (4UL << 8), NSPointerFunctionsIntegerPersonality NS_ENUM_AVAILABLE(10_5, 6_0) = (5UL << 8),
NSPointerFunctionsCopyIn NS_ENUM_AVAILABLE(10_5, 6_0) = (1UL << 16),};
defaultではhashとisEqual:を使って比較
速度比較10,000個のUUIDをaddObject
class timeNSArray 0.055016NSSet 0.023589NSHashTable 0.022918
速度比較ArrayにcontainsObject:を追加
class timeNSArray 3.670467NSSet 0.021289NSHashTable 0.021819
真意はNSPointerFunctionsWeakMemo
ry[NSHashTable hashTableWithOptions:NSPointerFunctionsWeakMemory];[NSHashTable weakObjectsHashTable];
Objectが破棄されると自動で削除
NSInteger max = 1000; @autoreleasepool { for (NSInteger i = 0; i < max; i++) { NSString *str = [NSUUID UUID].UUIDString; [ht addObject:str]; NSLog(@"count %ld", ht.allObjects.count); } }
NSLog(@"count %ld %@", ht.allObjects.count, ht.allObjects);
countは反映されないので、allObjects.countが良いかと
何に使おかUIScrollView.delegate
UIWebView.delegate
大人気!でもdelegateは1対1
1対多のパターンが欲しい
NJKScrollProxyパターン?_scrollProxy = [[NJKScrollFullScreen alloc] initWithForwardTarget:self]; // UIScrollViewDelegate andself.tableView.delegate = (id)_scrollProxy; // cast for surpress incompatible warnings_scrollProxy.delegate = self;
delegateは1対1の通知パターンなので仕方ない
1対多と言えばKVOcontentOffsetをKVOで監視したり
ドラッグのスピード等は独自実装しなければならない
KVOはおそらくassignで保持してるので、removeObserver:
忘れるとクラッシュする
そこでDelegatesパターン- (void)addDelegate:(id <NantokaDelegate>)delegate;- (void)removeDelegate:(id <NantokaDelegate>)delegate;- (void)removeAllDelegates;
addDelegate - NSArray- (void)addDelegate:(id <NantokaDelegate>)delegate { if ([self.delegates containsObject:delegate]) { return; } [self.delegates addObject:delegate];}
同じ通知を複数回 投げる必要はないのでcontainsObjectす
る
addDelegate - NSHashTable- (void)addDelegate:(id <NantokaDelegate>)delegate { [self.delegates addObject:delegate];}
スッキリ!
登録されたdelegatesに通知- (void)scrollViewDidScroll:(UIScrollView *)scrollView { for (id <UIScrollViewDelegate> delegate in self.delegates) { if ([delegate conformsToProtocol:@protocol(UIScrollViewDelegate)]) { if ([delegate respondsToSelector:@selector(scrollViewDidScroll:)]) { [delegate scrollViewDidScroll:scrollView]; } } }}
DegatesパターンにNSHashTableを使うと幸せに
なる理由delegatesをNSArrayで管理するとretainされる
delegateは基本的にasign < weak参照が良い
deallocでdelegate = nilする場合等、循環参照の問題
assignの時は非同期通信等、通信完了前にdelegateが破棄
された場合にクラッシュ
dealloc等でdelegate = nil する必要があった
weakなら何も起こらず安心
NSHashTableならweakで管理できるので解放いらない
delegatesパターンってあるの?
聞いたことないです
議論はちらほらあって、権限を移譲できる人が沢山いるの
は良くないとか
実はAppleが採用してたりとか?
とりあえずプロジェクト内を
検索してみた
あった!AFURLSessionManager
- (void)addDelegateForDownloadTask:(NSURLSessionDownloadTask *)downloadTask progress:(NSProgress * __autoreleasing *)progress destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler;- (void)removeAllDelegates;
delegatesはNSMutableDictionaryでした。
weak参照の通知と言えばRealmの更新通知
_token = [[RLMRealm defaultRealm] addNotificationBlock:^(NSString *notification, RLMRealm *realm) }];
_tokenを解放すると監視外れるので、weak参照でblockを保
持
delegatesではないけど、blockを何かにaddして保持してい
る
あった!NSHashTable *_notificationHandlers
こんなケースにも使えそうMemoryManager的な
+ (instansetype)sharedManager;- (void)addViewController:(UIViewController *)vc;- (NSArray *)leakedViewControllers;
- (NSArray *)leakedViewControllers { NSMutableArray *r = [@[] mutableCopy]; for (UIViewController *vc in self.hashTable.allObjects) { if (??? vc.parentViewController == nil ????) { [r addObject:vc]; } } return r;}
Leaks繋がなくてもデバッグできそう!
NSHashTableでDelegates まとめ
ユニークなコレクションを作る場合、速度はNSArrayより
高速、NSSetと同じ
NSHashTableを利用したdelegatesパターンならKVOの
removeObserver忘れのようなことも気にしないでよい
NSHashTableの使いどころ
KVO以外の方法で1対多の通知を実現したい場合
非同期処理のOperation管理
リークチェック等にも使えそう
Which
http://which.photos
Whichというアプリをリリースします
larabel, RealmでSQL書かずに実装しました
もちろんdelegatesパターン使いました