fuz*_*oat 10 iphone cocoa-touch objective-c nstimer
我想我会把这个作为一个单独的问题从我之前的 保留 - 重复 - 时间 - 后续访问中解决,因为讨论已经向前发展,使得一个新问题比另一个编辑更清晰:
场景是一个对象创建一个重复的NSTimer,让我们说在viewDidLoad中,一旦创建了NSTimer需要留在那里,所以它可以通过其他方法访问.
NSTimer *ti = [NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:@selector(updateDisplay:)
userInfo:nil
repeats:YES];
Run Code Online (Sandbox Code Playgroud)
我知道在创建时,runloop取得了NSTimer的所有权,最终在[ti invalidate];
调用时停止,删除和释放NSTimer .
由于我们需要以多种方法访问NSTimer,我们需要一些方法来保存参考以供将来使用,修订后的问题是:
// (1) Should the NSTimer be held using an owning reference (i.e.)
@property(nonatomic, retain) NSTimer *walkTimer;
[self setWalkTimer: ti];
...
...
// Cancel method
[[self walkTimer] invalidate;
[self setWalkTimer:nil];
...
...
// dealloc method
[walkTimer release];
[super dealloc];
Run Code Online (Sandbox Code Playgroud)
.
// (2) Should the NSTimer be held using a weak reference (i.e.)
@property(nonatomic, assign) NSTimer *walkTimer;
[self setWalkTimer: ti];
...
...
// Cancel method
[[self walkTimer] invalidate];
[self setWalkTimer:nil];
...
...
// dealloc method
[super dealloc];
Run Code Online (Sandbox Code Playgroud)
.
// (3) Use an iVar and rely on the runLoop holding (i.e. retaining) the timer
NSTimer *walkTimer;
NSTimer *walkTimer = [NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:@selector(updateDisplay:)
userInfo:nil
repeats:YES];
...
...
// Cancel method
[walkTimer invalidate];
walkTimer = nil;
Run Code Online (Sandbox Code Playgroud)
.
// (4) Something not listed above ...
Run Code Online (Sandbox Code Playgroud)
我很高兴只有(1)(2)(3)或(4),因为关于哪个最好的讨论已经写在其他线程上.似乎确实有很多相互矛盾的答案,所以我希望这个更具体的问题将有助于关注这种情况下最佳实践.
作为Apple NSTimer类参考文献的附注,5个示例代码项目中有4个使用分配给保留属性的NSTimers.以下是类参考示例显示的示例:
@property (nonatomic, retain) NSTimer *updateTimer;
updateTimer = [NSTimer scheduledTimerWithTimeInterval:.01 target:self selector:@selector(updateCurrentTime) userInfo:p repeats:YES];
...
...
// Cancel
[updateTimer invalidate];
updateTimer = nil;
...
...
// Dealloc method
[super dealloc];
[updateTimer release];
Run Code Online (Sandbox Code Playgroud)
**应该注意的是,在示例中,Apple直接分配iVar而不使用属性设置器.
dan*_*dee 18
在给出了更多的思考并在我的推理中找到一个重要的缺陷之后,我得出了一个不同的结论:
无论您是否拥有对需要使其无效的计时器的拥有或非拥有引用都无关紧要.这完全是品味问题.
交易破坏者是,计时器的目标是什么:
如果创建计时器的对象是其目标,那么管理该对象的生命周期就会变得更加脆弱:它不能简单地保留/释放托管,而是需要确保持有对该对象的最后一个引用的客户端使它在之前使计时器无效它处理它.
让我用几种对象图来说明这种情况:
如果yourObject 一次只由一个实例拥有,当它被正确处理时,可以避免这种情况:
通过取消正确处理:在通过发布处理yourObject之前,someClientObject在yourObject上调用cancelTimer方法.在该方法中,yourObject使workTimer失效,并且(如果它拥有workTimer)通过发布http://a.yfrog.com/img614/7428/p8af.png释放workTimer
但是现在,您如何解决以下情况?
多个所有者:在初始状态下进行设置,但现在有多个独立的clientObject,它们包含对象的引用http://a.yfrog.com/img619/3908/wqe.png
我知道,没有简单的答案!(不是后者必须多说,但......)
所以我的建议是......
yourObject
定时器(因为这是避免因直接失效,他们访问的定时器客户端崩溃的唯一办法),并提供自己的二传手.在我看来,重新安排一个计时器并不是打破封装的好理由:如果你需要这样做,就提供一个mutator.someClientObject
类或 - 如果可以使用它 - 通过MAZeroingWeakReference?)我为第一次讨论中的白痴而道歉,并要感谢Daniel Dickison和Rob Napier的耐心.
所以这是我从现在开始处理计时器的方式:
// NSTimer+D12WeakTimerTarget.h:
#import <Foundation/NSTimer.h>
@interface NSTimer (D12WeakTimerTarget)
+(NSTimer *)D12scheduledTimerWithTimeInterval:(NSTimeInterval)ti weakTarget:(id)target selector:(SEL)selector userInfo:(id)userInfo repeats:(BOOL)shouldRepeat logsDeallocation:(BOOL)shouldLogDealloc;
@end
// NSTimer+D12WeakTimerTarget.m:
#import "NSTimer+D12WeakTimerTarget.h"
@interface D12WeakTimerTarget : NSObject {
__weak id weakTarget;
SEL selector;
// for logging purposes:
BOOL logging;
NSString *targetDescription;
}
-(id)initWithTarget:(id)target selector:(SEL)aSelector shouldLog:(BOOL)shouldLogDealloc;
-(void)passthroughFiredTimer:(NSTimer *)aTimer;
-(void)dumbCallbackTimer:(NSTimer *)aTimer;
@end
@implementation D12WeakTimerTarget
-(id)initWithTarget:(id)target selector:(SEL)aSelector shouldLog:(BOOL)shouldLogDealloc
{
self = [super init];
if ( !self )
return nil;
logging = shouldLogDealloc;
if (logging)
targetDescription = [[target description] copy];
weakTarget = target;
selector = aSelector;
return self;
}
-(void)dealloc
{
if (logging)
NSLog(@"-[%@ dealloc]! (Target was %@)", self, targetDescription);
[targetDescription release];
[super dealloc];
}
-(void)passthroughFiredTimer:(NSTimer *)aTimer;
{
[weakTarget performSelector:selector withObject:aTimer];
}
-(void)dumbCallbackTimer:(NSTimer *)aTimer;
{
[weakTarget performSelector:selector];
}
@end
@implementation NSTimer (D12WeakTimerTarget)
+(NSTimer *)D12scheduledTimerWithTimeInterval:(NSTimeInterval)ti weakTarget:(id)target selector:(SEL)selector userInfo:(id)userInfo repeats:(BOOL)shouldRepeat logsDeallocation:(BOOL)shouldLogDealloc
{
SEL actualSelector = @selector(dumbCallbackTimer:);
if ( 2 != [[target methodSignatureForSelector:aSelector] numberOfArguments] )
actualSelector = @selector(passthroughFiredTimer:);
D12WeakTimerTarget *indirector = [[D12WeakTimerTarget alloc] initWithTarget:target selector:selector shouldLog:shouldLogDealloc];
NSTimer *theTimer = [NSTimer scheduledTimerWithTimeInterval:ti target:indirector selector:actualSelector userInfo:userInfo repeats:shouldRepeat];
[indirector release];
return theTimer;
}
@end
Run Code Online (Sandbox Code Playgroud)
原件(完整披露):
您从其他帖子中了解我的意见:
没有理由拥有预定计时器的参考(并且bbum似乎同意).
也就是说,您的选项2和3基本相同.(有涉及额外的消息yourObject
了yourObject
,但我不知道如果编译器不会优化该走并直接访问实例变量,但是呢......)
归档时间: |
|
查看次数: |
4530 次 |
最近记录: |