Objective c 当我们执行NSTimer无效时发生了什么?

Objective c 当我们执行NSTimer无效时发生了什么?,objective-c,cocoa,nstimer,Objective C,Cocoa,Nstimer,然后应用程序崩溃,因为EXC\u访问错误 苹果的文件说 此方法是从nsrunlop对象中删除计时器的唯一方法。NSRunLoop对象在invalidate方法返回之前或稍后某个时间删除对计时器的强引用。如果它配置了目标和用户信息对象,接收器也会删除对这些对象的强引用。 苹果告诉我们在计时器失效后不要使用userInfo,但为什么呢 计时器的引用计数由程序员控制,userInfo(我尝试将属性用作userInfo,而不是使用常量字符串)也是一样的 如果我们放置一个符号断点,比如-[NSTimer

然后应用程序崩溃,因为
EXC\u访问错误

苹果的文件说

此方法是从nsrunlop对象中删除计时器的唯一方法。NSRunLoop对象在invalidate方法返回之前或稍后某个时间删除对计时器的强引用。如果它配置了目标和用户信息对象,接收器也会删除对这些对象的强引用。

苹果告诉我们在计时器失效后不要使用
userInfo
,但为什么呢

计时器的引用计数由程序员控制,userInfo(我尝试将属性用作userInfo,而不是使用常量字符串)也是一样的

如果我们放置一个符号断点,比如
-[NSTimer userinfo]
,我们可以得到崩溃信息,比如

self.timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(timeCall:) userInfo:self.strong repeats:YES];
[self.timer invalidate];
NSLog(@"%p",[self.timer userInfo]);
CoreFoundation`-[\uu NSCFTimer userInfo]:
0x7fff20384d32:pushq%rbp
0x7fff20384d33:movq%rsp%rbp
0x7fff20384d36:pushq%rbx
0x7fff20384d37:subq$0x38,%rsp
0x7fff20384d3b:movq 0x5fca7d6e(%rip),%rax;(无效*)0x00007fff86d060e0:uu堆栈_uchk_u保护
0x7fff20384d42:movq(%rax),%rax
0x7fff20384d45:movq%rax,-0x10(%rbp)
0x7fff20384d49:leaq-0x38(%rbp),%rbx
0x7fff20384d4d:movq$0x0,(%rbx)
0x7fff20384d54:movq%rbx%rsi
0x7fff20384d57:调用0x7fff203a6ff9;CFRunLoopTimerGetContext
0x7fff20384d5c:movq 0x8(%rbx),%rax
->0x7fff20384d60:movq 0x18(%rax),%rax
0x7fff20384d64:movq 0x5fca7d45(%rip),%rcx;(无效*)0x00007fff86d060e0:uu堆栈_uchk_u保护
0x7fff20384d6b:movq(%rcx),%rcx
0x7fff20384d6e:cmpq-0x10(%rbp),%rcx
0x7fff20384d72:jne 0x7fff20384d7b;
0x7fff20384d74:addq$0x38,%rsp
0x7fff20384d78:popq%rbx
0x7fff20384d79:popq%rbp
0x7fff20384d7a:retq
0x7fff20384d7b:callq 0x7fff204c318e;符号存根:\堆栈\通道\失败

我知道nsrunlop和NSTimer之间的关系,但是这个userinfo属性呢?我想可能是为了存档
只读
关键字。我们如何研究
NSTimer
的内部实现,或者有什么方法可以探索呢?

如果它配置了目标和用户信息对象,接收器也会删除对这些对象的强引用。
因此self.timer为零,并且没有对userInfo的引用。
self.timer
表示您使用
NSTimer
创建了一个属性。设置内部
\u定时器=nil有帮助紧接着
[self.timer invalidate]。如果(!\u timer)self.timer=[NSTimer scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:],它将帮助在self.timer
上重新应用新的NSTimer从手册中,我希望
userInfo
的指针最坏情况是,如果发布了,就返回0。虽然
userInfo
被定义为头文件中的一个属性,但我从崩溃转储中怀疑,它实际上是一条带有礼貌检查的消息,抛出了该异常,或者-gasp-一个可怕的错误。由于消息似乎调用了
CFRunLoopTimerGetContext
,您需要预先分配内存,我想可能只是一个bug。尽管如此,使用无效的计时器做任何事情都不会赢得框架上众多bug修复者的同情。@OlSen,在我编辑这个问题时,计时器的引用计数和userInfo的引用计数都是由程序员控制的。
userInfo
属性是
-[\u\nschftimer userInfo]
的语法糖。显然,
userInfo
存储在上下文的
info
中,并且
invalidate
删除此
info
。计时器没有指向
invalidate
之后的
userInfo
对象的指针。
CoreFoundation`-[__NSCFTimer userInfo]:
    0x7fff20384d32 <+0>:  pushq  %rbp
    0x7fff20384d33 <+1>:  movq   %rsp, %rbp
    0x7fff20384d36 <+4>:  pushq  %rbx
    0x7fff20384d37 <+5>:  subq   $0x38, %rsp
    0x7fff20384d3b <+9>:  movq   0x5fca7d6e(%rip), %rax    ; (void *)0x00007fff86d060e0: __stack_chk_guard
    0x7fff20384d42 <+16>: movq   (%rax), %rax
    0x7fff20384d45 <+19>: movq   %rax, -0x10(%rbp)
    0x7fff20384d49 <+23>: leaq   -0x38(%rbp), %rbx
    0x7fff20384d4d <+27>: movq   $0x0, (%rbx)
    0x7fff20384d54 <+34>: movq   %rbx, %rsi
    0x7fff20384d57 <+37>: callq  0x7fff203a6ff9            ; CFRunLoopTimerGetContext
    0x7fff20384d5c <+42>: movq   0x8(%rbx), %rax
->  0x7fff20384d60 <+46>: movq   0x18(%rax), %rax
    0x7fff20384d64 <+50>: movq   0x5fca7d45(%rip), %rcx    ; (void *)0x00007fff86d060e0: __stack_chk_guard
    0x7fff20384d6b <+57>: movq   (%rcx), %rcx
    0x7fff20384d6e <+60>: cmpq   -0x10(%rbp), %rcx
    0x7fff20384d72 <+64>: jne    0x7fff20384d7b            ; <+73>
    0x7fff20384d74 <+66>: addq   $0x38, %rsp
    0x7fff20384d78 <+70>: popq   %rbx
    0x7fff20384d79 <+71>: popq   %rbp
    0x7fff20384d7a <+72>: retq   
    0x7fff20384d7b <+73>: callq  0x7fff204c318e            ; symbol stub for: __stack_chk_fail