去年封的一個圖片輪播的, 這兩天在忙着給從新封裝一下, 增長更多的方法, 有更多個性化的設置, 增長了網絡請求圖片的輪播. 從新封裝, 這個過程還算順利, 可是到計時器那塊卡住了.git
WHImagePlayer圖片輪播和圖片瀏覽器: https://github.com/hell03W/WHImagePlayer, 歡迎star支持一下, 若是有任何問題歡迎issue給我.github
問題是這樣的:瀏覽器
簡單來講, 其實就是計時器, 我用的NSTimer, 是在一個自定義view中建立NSTimer的, 若是是在控制器中, 能夠在viewWillDisappear:中執行NSTimer的invalidate
方法, timer對象是能夠被正常銷燬的, 可是在自定義的view裏面沒有那樣的方法! 有人會說能夠將target設置成__weak
類型的就能夠了嘛 ! 我也是那樣認爲的, 但是試驗證實, 那樣是不行的(要是那麼簡單, 也不必寫個blog來記錄了).網絡
通過在網上查找資料, 和本身的思考, 最終總結了幾種可行方案:app
方案一:oop
以下代碼所示, 使用dispatch_after
能夠完美解決, 可是須要注意的是, 在block內部, 使用self
時候必須使用weakSelf, 若是直接使用self, 仍是不會被釋放掉的.spa
__weak typeof(self) weakSelf = self; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [UIView animateWithDuration:0.3 animations:^{ weakSelf.imageScrollView.contentOffset = CGPointMake(weakSelf.width*2, 0); } completion:^(BOOL finished) { if (finished) { [weakSelf scrollViewDidEndDecelerating:weakSelf.imageScrollView]; [weakSelf setupTimer]; } }]; });
方案2:code
使用一個假冒的對象做爲target. 原理也不復雜, 建立一個類, 讓新的類擁有self的弱引用, 經過這個類的方法, 將須要做爲target的"self"
和要執行的方法的名字"selector"
, 傳入新的類內部, 在新的類內部, 調用"self"
的"selector"
方法, 在自定義view的NSTimer方法中調用新的類的調用外部類方法的方法.orm
上代碼:對象
WHTimerTarget.h
#import <Foundation/Foundation.h> @interface WHTimerTarget : NSObject /**1. 調用這個方法 傳入target和selector和時間, 就會間隔timeInterval秒執行target的selector方法. 內部使用NSTimer實現, 主要是爲了解決, NSTimer會出現循環引用的問題 */ + (void)addTarget:(id)target selector:(SEL)selector timeInterval:(NSTimeInterval)timeInterval; /// 2. 若是如要NSTimer寫在本類外面, 可使用這個方法 + (instancetype)timerTarget:(id)target selector:(SEL)selector; - (void)timerDidFire:(NSTimer *)timer; @end
WHTimerTarget.m
#import "WHTimerTarget.h" @implementation WHTimerTarget { __weak id _target; SEL _selector; } - (instancetype)initWithTarget:(id)target selector:(SEL)selector { self = [self init]; _target = target; _selector = selector; return self; } + (instancetype)timerTarget:(id)target selector:(SEL)selector { return [[self alloc] initWithTarget:target selector:selector]; } - (void)timerDidFire:(NSTimer *)timer { if(_target) { [_target performSelector:_selector withObject:timer]; } else { [timer invalidate]; } } + (void)addTarget:(id)target selector:(SEL)selector timeInterval:(NSTimeInterval)timeInterval { id timerTarget = [[self alloc] initWithTarget:target selector:selector]; NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:timeInterval target:timerTarget selector:@selector(timerDidFire:) userInfo:nil repeats:YES]; [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; } @end
如上代碼所示, 就是新的類, 僞target的所有代碼. 使用的方法有兩種, 以下:
1, 使用方法: id target = [TimerTarget timerTarget:<#self#> selector:@selector(<#automaticScroll:#>)]; NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:<#self.autoScrollTimeInterval#> target:target selector:@selector(timerDidFire:) userInfo:nil repeats:YES]; 2, 使用方法: [TimerTarget addTarget:<#self#> selector:@selector(<#automaticScroll:#>) timeInterval:<#3#>];
寫在後面的:
目前爲止, 我只發現這兩種比較好用的方法, 若是誰有更好的方案, 歡迎留言交流 .