gpt4 book ai didi

iphone - 重复 NSTimer、弱引用、拥有引用或 iVar?

转载 作者:太空狗 更新时间:2023-10-30 03:25:39 24 4
gpt4 key购买 nike

我想我会把它作为一个独立于我之前的问题提出来
retaining-repeating-nstimer-for-later-access随着讨论的推进,新问题比另一个编辑更清晰:

场景是一个对象创建一个重复的 NSTimer,比如在 viewDidLoad 中,一旦创建,NSTimer 需要保留,以便其他方法可以访问它。

NSTimer *ti = [NSTimer scheduledTimerWithTimeInterval:1 
target:self
selector:@selector(updateDisplay:)
userInfo:nil
repeats:YES];

我知道,当创建 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];

.
// (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];

.
// (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;

.
// (4) Something not listed above ...

我很高兴(1)(2)(3)或(4),因为关于哪个最好的讨论已经写在 Other上。线。似乎确实有很多相互矛盾的答案,所以我希望这个更具体的问题将有助于关注在这种情况下可能的最佳实践。

编辑:

作为 Apple NSTimer Class Reference 中的旁注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];

** 应该注意的是,在示例中,Apple 是直接分配 iVar 而不是使用属性 setter 。

最佳答案

在仔细考虑并发现我的推理中的一个重要缺陷之后,我得出了一个不同的结论:

无关紧要,您是否持有对需要无效的计时器的拥有或非拥有引用。这完全是一个品味问题。

交易破坏者是,计时器的目标是什么:

如果创建计时器的对象是它的目标,则管理该对象的生命周期变得更加脆弱:它不能简单地被保留/释放管理,相反,您需要确保持有对该对象的最后一个引用的客户端使其在之前使计时器失效它处理它。

让我用几个对象图来说明这种情况:

  • 您从设置计时器并将自己设置为目标的状态开始。定时器设置:yourObjectsomeClientObject 所有.并行存在当前运行循环和调度定时器数组。 setupTimer 方法在 yourObject 上被调用:

  • 结果是以下初始状态。除了前状态yourObject现在有对 workTimer 的引用(拥有与否) ,后者又拥有 yourObject .此外,workTimer由 run-loopscheduledTimers 数组拥有:

  • 所以现在你将使用这个对象,但是当你完成它并简单地释放它时,你最终会得到简单的释放泄漏:在 someClientObject 之后处置 yourObject通过一个简单的发布,yourObject与对象图分离,但通过 workTimer 保持事件状态. workTimeryourObject被泄露了!

  • 在哪里泄漏对象(和计时器),因为 runloop 使计时器保持事件状态,这反过来又保持对您的对象的拥有引用。

    如果 yourObject 可以避免这种情况仅由 拥有单个实例 一次,当它被正确处置时通过取消正确处置:在处置之前 yourObject通过发布, someClientObject调用 cancelTimer yourObject 上的方法。在该方法中, yourObject 无效 workTimer并且(如果它拥有 workTimer )通过 release 处理 workTimer:

    但是现在,您如何解决以下情况?
    多个所有者:像初始状态一样设置,但现在有多个独立 clientObjects持有对 yourObject 的引用



    没有简单的答案,我知道! (倒不是后者要多说,而是……)

    所以我的建议是...
  • 不要让你的计时器成为一个属性/不要为它提供访问器!相反,保持它的私有(private)性(我认为在现代运行时你可以在类扩展中定义 ivar)并且只从一个对象处理它。 (你可以保留它,如果你觉得这样做更舒服,但绝对没有必要。)
  • 警告:如果您绝对需要从另一个对象访问计时器,请设置属性 retain计时器(因为这是避免客户端直接使他们访问的计时器无效而导致崩溃的唯一方法)提供你自己的二传手。在我看来,重新安排计时器并不是打破封装的好理由:如果需要,请提供一个 mutator。
  • 将计时器设置为自我以外的目标。 (有很多方法可以这样做。也许通过编写一个通用的 TimerTarget 类,或者——如果你可以使用它——通过一个 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

    原装 (全面披露):

    你知道我的意见来自 your other post :

    没有理由拥有预定计时器(和 bbum seems to agree )的引用。

    也就是说,您的选项 2 和 3 基本相同。 (在 [self setWalkTimer:nil] 中涉及额外的消息传递,超过 walkTimer = nil,但我不确定编译器是否不会优化它并直接访问 ivar,但是......)

    关于iphone - 重复 NSTimer、弱引用、拥有引用或 iVar?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4945028/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com