モバイル製品の安定性NSTimer
6504 ワード
NSTimerは日常の仕事でよく使われています.いくつかの面でよく使われていますタイミング繰返しタスク 遅延タスク Banner運用コントロールスライド 繰り返しリフレッシュインターフェース これらの面では、ほとんどのアプリケーションが直面しているニーズですが、NSTimerには間接的に多くのcrashを招き、これらのcrashがどこのコードによるのか分からない非常に危険な場所があります.
NSTimerの危険原因
一般的な開発者はNSTimerを以下のように使用し,runloop関連の操作をカプセル化し,より使いやすいようにscheduleの先頭の方法を使用するのが一般的である.
以上のコードは,非常に正常なNSTimer実装方式である.しかし問題はtargetがselfであることです.システムのNSTimer関数に注目する必要があります.strongがselfに住んでいますか??実験により,システムは確かにselfにstrongが住んでおり,これにより循環参照とメモリ漏洩を招くことが分かった.
A classでは、NSTimerが継続的に実行されているTBTimerTestObjectを定義します.
TBTimerTestObjectファイル
実行コードの結果
結果としてメモリリークがある
NSTimerの隠れた危険がもたらす危害
一般的に、メモリの漏洩が発生しても大きな問題は発生しませんが、以前のtimerオブジェクトのため、内部がうまく処理されていないため、timerdidfiredが絶えず実行されると、深刻な危険が発生し、crashも発生します.共有メモリ処理 NSArray/NSDictoryに対する処理 webに対する処理 等 そのため、メモリの漏洩の問題を解決するには、非常に重要です.
ソリューション
NSTimerメモリの漏洩の問題では、targetがselfをhookし、selfとtimerのループ参照を引き起こすことが重要です.では、解決したい方法は、ループリファレンスの問題を解決することだけです.
使用方法:
うん、簡単だよ.TBWeakTimerTargetがNSTimerの使用を保護すると、NSTimerとSelfが循環参照しないことが保証されます.
要するに、モバイル製品の安定性は製品性能の重要な指標である.
【叁省http://blog.csdn.net/bjtufang 転載は出典を明記し、労働成果を尊重してください.
NSTimerの危険原因
一般的な開発者はNSTimerを以下のように使用し,runloop関連の操作をカプセル化し,より使いやすいようにscheduleの先頭の方法を使用するのが一般的である.
@property (nonatomic, strong) NSTimer* timer;
...
_timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerDidFire:) userInfo:nil repeats:YES];
...
- (void)timerDidFire:(NSTimer*)timer
{
NSLog(@"%@", @"timerDidFire:");
}
以上のコードは,非常に正常なNSTimer実装方式である.しかし問題はtargetがselfであることです.システムのNSTimer関数に注目する必要があります.strongがselfに住んでいますか??実験により,システムは確かにselfにstrongが住んでおり,これにより循環参照とメモリ漏洩を招くことが分かった.
A classでは、NSTimerが継続的に実行されているTBTimerTestObjectを定義します.
- (BOOL)TestTimterInAClass
_obj = [[TBTimerTestObject alloc] init];
[self performSelector:@selector(timerDidFired:) withObject:nil afterDelay:1];
return YES;
}
- (void)timerDidFired:(NSTimer*)timer
{
_obj = nil;
NSLog(@"%@", @" AppDelegate timerDidFired");
}
TBTimerTestObjectファイル
@interface TBTimerTestObject ()
@property (nonatomic, weak) NSTimer* timer;
@end
@implementation TBTimerTestObject
- (void)dealloc
{
NSLog(@"sssss");
}
- (id)init
{
self = [super init];
if (self) {
_timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerDidFire:) userInfo:nil repeats:YES];
}
return self;
}
- (void)timerDidFire:(NSTimer*)timer
{
NSLog(@"%@", @"1111111");
}
@end
実行コードの結果
11111111
AppDelegate timerDidFired
11111111
11111111
11111111
11111111
結果としてメモリリークがある
NSTimerの隠れた危険がもたらす危害
一般的に、メモリの漏洩が発生しても大きな問題は発生しませんが、以前のtimerオブジェクトのため、内部がうまく処理されていないため、timerdidfiredが絶えず実行されると、深刻な危険が発生し、crashも発生します.
ソリューション
NSTimerメモリの漏洩の問題では、targetがselfをhookし、selfとtimerのループ参照を引き起こすことが重要です.では、解決したい方法は、ループリファレンスの問題を解決することだけです.
#import <Foundation/Foundation.h>
@interface TBWeakTimerTarget : NSObject
- (instancetype) initWithTarget: (id)target andSelector:(SEL) selector;
- (void)timerDidFire:(NSTimer *)timer;
@end
#import "TBWeakTimerTarget.h"
@implementation TBWeakTimerTarget
{
__weak id _target;
SEL _selector;
}
- (instancetype) initWithTarget: (id) target andSelector: (SEL) selector
{
self = [super init];
if (self) {
_target = target;
_selector = selector;
}
return self;
}
- (void) dealloc
{
NSLog(@"TBWeakTimerTarget dealloc");
}
- (void)timerDidFire:(NSTimer *)timer
{
if(_target)
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[_target performSelector:_selector withObject:timer];
#pragma clang diagnostic pop
}
else
{
[timer invalidate];
}
}
@end
使用方法:
TBWeakTimerTarget* timerTarget = [[TBWeakTimerTarget alloc] initWithTarget:self andSelector:@selector(timerDidFire:)];
_timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:timerTarget selector:@selector(timerDidFire:) userInfo:nil repeats:YES];
うん、簡単だよ.TBWeakTimerTargetがNSTimerの使用を保護すると、NSTimerとSelfが循環参照しないことが保証されます.
要するに、モバイル製品の安定性は製品性能の重要な指標である.
【叁省http://blog.csdn.net/bjtufang 転載は出典を明記し、労働成果を尊重してください.