- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我创建了一个弱目标定时器类,当目标被释放时,定时器不会触发并自动失效。代码是这样的:
//ViewController.m
@interface TestObj : NSObject
@end
@implementation TestObj
- (id)init
{
self = [super init] ;
if (self) {
NSLog(@"%@ %@", self, NSStringFromSelector(_cmd)) ;
}
return self ;
}
- (void)dealloc
{
NSLog(@"%@ %@", self, NSStringFromSelector(_cmd)) ;
}
- (void)timerFiredForInvocation:(id)obj
{
NSLog(@"%@, %@", obj, NSStringFromSelector(_cmd)) ;
}
@end
@interface ViewController ()
@property (nonatomic, strong) WTTimer *timer1 ;
@property (nonatomic, strong) WTTimer *timer2 ;
@property (nonatomic, strong) TestObj *obj ;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_obj = [[TestObj alloc] init] ;
NSMethodSignature *methodSig = [_obj methodSignatureForSelector:@selector(timerFiredForInvocation:)] ;
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig] ;
invocation.target = _obj ;
invocation.selector = @selector(timerFiredForInvocation:) ;
id objArgument = [[TestObj alloc] init] ;
[invocation setArgument:&objArgument atIndex:2] ;
_timer2 = [WTTimer scheduledTimerWithTimeInterval:2.0 invocation:invocation repeats:YES] ;
NSLog(@"timer is scheduled") ;
// delay to set self.obj to nil and make it be deallocated
[self performSelector:@selector(delay) withObject:nil afterDelay:3.0] ;
}
- (void)delay
{
NSLog(@"%@ %@", self, NSStringFromSelector(_cmd)) ;
self.obj = nil ;
}
@end
//WTTimer.m
@class TimerDelegateObject ;
@protocol WTTimerDelegate <NSObject>
- (void)wtTimerFired:(TimerDelegateObject *)obj ;
@end
@interface TimerDelegateObject : NSObject
@property (nonatomic, weak) id<WTTimerDelegate> delegate ;
- (void)timerFired:(NSTimer *)timer ;
@end
@implementation TimerDelegateObject
- (void)timerFired:(NSTimer *)timer
{
[_delegate wtTimerFired:self] ;
}
@end
@interface WTTimer () <WTTimerDelegate>
@property (nonatomic, strong) NSTimer *timer ;
// target and selector
@property (nonatomic, weak) id wtTarget ;
@property (nonatomic) SEL selector ;
// for NSInvocation
@property (nonatomic, strong) NSInvocation *invocation ;
@end
@implementation WTTimer
- (instancetype)initWithFireDate:(NSDate *)date
interval:(NSTimeInterval)seconds
target:(id)target
selector:(SEL)aSelector
userInfo:(id)userInfo
repeats:(BOOL)repeats
{
self = [super init] ;
if (self) {
_timer = [[NSTimer alloc] initWithFireDate:date interval:seconds target:target selector:aSelector userInfo:userInfo repeats:repeats] ;
}
return self ;
}
+ (WTTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo
{
TimerDelegateObject *delegateObj = [[TimerDelegateObject alloc] init] ;
NSDate *dateFire = [NSDate dateWithTimeIntervalSinceNow:ti] ;
WTTimer *timer = [[WTTimer alloc] initWithFireDate:dateFire
interval:ti
target:delegateObj
selector:@selector(timerFired:)
userInfo:nil
repeats:yesOrNo] ;
delegateObj.delegate = timer ;
// config WTTimer
timer.wtTarget = invocation.target ; // timer.wtTarget is weak
invocation.target = delegateObj ;// I change the target to delegateObj, so [invocation retainArguments] won't retain the original target
[invocation retainArguments] ;
timer.invocation = invocation ;
return timer ;
}
+ (WTTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo
{
WTTimer *timer = [WTTimer timerWithTimeInterval:ti invocation:invocation repeats:yesOrNo] ;
if (timer) {
[[NSRunLoop currentRunLoop] addTimer:timer.timer forMode:NSDefaultRunLoopMode] ;
}
return timer ;
}
- (void)wtTimerFired:(TimerDelegateObject *)obj
{
if (_wtTarget) {
if (_invocation) {
[_invocation invokeWithTarget:_wtTarget] ;
} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[_wtTarget performSelector:_selector withObject:self] ;
#pragma clang diagnostic pop
}
} else {
// the target is deallocated, the timer should be invalidated
[self.timer invalidate] ;
NSLog(@"the target is deallocated, invalidate the timer") ;
}
}
- (NSDate *)fireDate
{
return [_timer fireDate] ;
}
- (void)setFireDate:(NSDate *)fireDate
{
_timer.fireDate = fireDate ;
}
- (NSTimeInterval)timeInterval
{
return [_timer timeInterval] ;
}
- (void)fire
{
return [_timer fire] ;
}
- (void)invalidate
{
[_timer invalidate] ;
}
- (BOOL)isValid
{
return [_timer isValid] ;
}
- (id)userInfo
{
return _timer.userInfo ;
}
@end
ViewController
的delay
方法中存在一个问题,当self.obj = nil
执行时,_obj
应该被释放,但事实上,它不是,我不知道为什么。除了ViewController中的obj属性,没有强引用,但是为什么不能deallocated。
注意 1:如果我在 timerWithTimeInterval:invocation:repeats:
中删除这行代码:[invocation retainArguments] ;
,它将被释放。
注意2:如果我不在runloop中安排定时器,目标对象也会被释放。
+ (WTTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo
{
WTTimer *timer = [WTTimer timerWithTimeInterval:ti invocation:invocation repeats:yesOrNo] ;
if (timer) {
// [[NSRunLoop currentRunLoop] addTimer:timer.timer forMode:NSDefaultRunLoopMode] ;
}
return timer ;
}
如果您对此感兴趣,我将代码发布在 https://github.com/kudocc/WTTimer 中.我花了一天的时间试图弄清楚但没有用,任何人都可以帮助我吗?谢谢你的时间。
最佳答案
要回答这个问题:行 [_invocation invokeWithTarget:_wtTarget];
是您设置对 TestObj
目标的额外强引用的地方。
documentation对于 [NSInvocation invokeWithTarget:]
说:
Sets the receiver’s target, sends the receiver’s message (with arguments) to that target, and sets the return value.
在我看来,如果您在 NSInvocation
上调用了 -retainArguments
,那么您随后设置了一个新的 target
, 的实现code>NSInvocation
应该(并且确实)释放其旧的 target
并保留其新的。
这也解释了您在两个笔记中观察到的内容:
Note1: If I remove this line of code:
[invocation retainArguments];
intimerWithTimeInterval:invocation:repeats:
, it will be deallocated.
从不调用 -retainArguments
,NSInvocation
将不会保留其新的 target
。
Note2: If I don't schedule the timer in runloop, the target object is deallocated too.
如果您不安排计时器,则永远不会调用 -invokeWithTarget
。
关于ios - NSInvocation 中的目标应该被释放,但它没有,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30524466/
我正在使用 NSInvocation 调用一个我在编译时不知道的方法。 它工作正常,因为我没有找到如何传递 NSError** 类型的参数。 举个例子,假设我想从 NSFileManager 调用方法
以下代码抛出异常。 vcClass 是一个 Class 对象(继承自 UIViewController)。 Self 包含 我的实现 viewWillAppear: SEL viewWillAppea
既然可以直接调用方法,为什么还要使用 NSInvocation?需要问这个问题是因为我无法理解需要使用这个类。与仅调用如下方法相比,使用它有什么优势。 [myArray addObject:mySt
这个问题在这里已经有了答案: NSInvocation getReturnValue: called inside forwardInvocation: makes the returned obj
我想在未来安排一个函数调用。我正在使用 Swift。 我想回调一个私有(private)方法并返回一个 Promise(来自 PromiseKit) 我见过的所有例子都用到了 NSTimer.sche
什么是NSInspiration?何时以及如何使用它? 最佳答案 NSInvocation是消息发送的具体化。换句话说,它是一个代表消息发送的对象。 假设您的 Foo 类有一个名为 -[Foo foo
我创建了一个弱目标定时器类,当目标被释放时,定时器不会触发并自动失效。代码是这样的: //ViewController.m @interface TestObj : NSObject @end @im
有谁知道如何将 NSInvocation 的参数设置为 nil ?我正在尝试使用 OCMock,我希望这种期望返回 nil。问题是调用该方法时我需要做一些其他事情,正如您在示例中看到的那样,这就是为什
我有一个方法,它采用类似这样的可变参数,参数以 nil 结尾。 -(void)manyParams:(NSString *)st, ... { va_list argList; va_
我想使用一个将指向 NSError 对象的指针作为参数的方法来创建一个 NSInvocation 对象。这方面的一个例子是方法 - - (BOOL)writeToFile:(NSString *)pa
下面是我从Apple的“Timer Programming Topics”看到的示例代码: NSMethodSignature *methodSignature = [self methodSigna
我如何(或什至可以)将 nil 参数传递给 NSInvocation 对象? 我试着这样做: NSMethodSignature* signature = [AClass instanceMethod
我正在尝试在 Swift 中创建一个可重用的测试工具,子类将扩展测试工具以提供被测实例,并且可以添加它们自己的特定于子类的测试方法,如下所示: class FooTestHarness: XCTest
NSInvocation 究竟是如何工作的?有好的介绍吗? 我在理解以下代码(来自 Cocoa Programming for Mac OS X,第 3 版)的工作原理方面特别有问题,但我也能够独立于
我使用运行时特性向类中添加了一个类方法,但是NSInvocation 无法使用该方法。我的代码是这样的: id metaClass = object_getClass((id)protocolClas
我对 NSInvocation 有一个奇怪的问题。当网络操作完成时,我将它用作返回回调。让我更详细地解释一下前面的句子: 我正在使用通过 TCP 套接字工作的定制网络协议(protocol),并且我有
我认为我犯了一个根本性的错误,但我一生都看不到它。 我正在从 C++ 类(已锁定)中调用 Objective-C 对象的方法。我正在使用 NSInvocation 来防止我不得不编写数百个方法来访问这
我们有以下方法,适用于对象。它接受一个对象的方法并将结果放在 returnValueContainer 中: + (void)invokePrivateMethod:(SEL)selector ret
我收到这条消息: “(null):无法识别的选择器发送到类 0x3f52e824” 我试过的基本代码: SEL sel = @selector(applyProperties:toObject:);
我试图将 block 参数传递给 NSInvocation,但应用程序崩溃了。调用发出网络请求并调用成功或失败 block 。我认为问题在于 block 在网络请求完成之前被释放。我设法让它与一些 B
我是一名优秀的程序员,十分优秀!