iOS NSTimer 순환 참조 방법

현재 컨트롤 러(ViewController)의 view 에 사용자 정의 view(LXFTimer View)를 추 가 했 습 니 다.LXFTimer View 는 성공 적 으로 생 성 된 후에 타이머 NSTimer 를 추가 하고 RunLoop 에 가입 하여 작업 을 시 작 했 습 니 다.현재 컨트롤 러 에서 LXFTimer View 를 제거 한 후에 도 타이머 가 작 동 하고 LXFTimer View 의 dealloc 는 호출 되 지 않 았 습 니 다.
코드
LXFTimerView.m

#import "LXFTimerView.h"
@interface LXFTimerView()
/**     */
@property(nonatomic, weak) NSTimer *timer;
@end

@implementation LXFTimerView
- (instancetype)initWithFrame:(CGRect)frame {
  if (self = [super initWithFrame:frame]) {
    [self addTimer];
  }
  return self;
}

- (void)dealloc {
  NSLog(@"LXFTimerView - dealloc");
  [self removeTimer];
}

#pragma mark -      
/**         */
- (void)addTimer {
  //      
  if (self.timer) { return; }
  self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(log) userInfo:nil repeats:YES];
  [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}
/**       */
- (void)removeTimer {
  [self.timer invalidate];
  self.timer = nil;
}
- (void)log {
  NSLog(@"    -- %s", __func__);
}
@end
ViewController.m

#import "ViewController.h"
#import "LXFTimerView.h"
@interface ViewController ()
/** timerView */
@property(nonatomic, weak) LXFTimerView *timerView;
@end

@implementation ViewController
- (void)viewDidLoad {
  [super viewDidLoad];
  LXFTimerView *timerView = [[LXFTimerView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 200)];
  timerView.backgroundColor = [UIColor orangeColor];
  self.timerView = timerView;
  [self.view addSubview:timerView];  
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
  [self.timerView removeFromSuperview];
}
@end
인용 관계

문 제 는 LXFTimerView 와 NSTimer 사이 에서 타 이 머 를 만 들 때 실 행 됩 니 다.

[NSTimer scheduledTimerWithTimeInterval: target: selector: userInfo: repeats:];
LXFTimer View 를 강하 게 인용 합 니 다.뭐라고 요?내 가 어떻게 알 아?아래 그림 을 보다

타이머 가 종 료 될 때 까지 target 에 대한 강 한 인용 을 유지 합 니 다.그런데 왜 LXFTimer View 의 timer 속성 은 weak 를 사용 합 니까?서 두 르 지 마 세 요.곧 나 올 겁 니 다~
해결 방안
타이머 가 다른 대상 을 가리 키 며 LXFTimerView 에서 실행 해 야 할 방법 을 실행 하도록 합 니 다.인용 관 계 는 아래 그림 과 같다.

NSObject 에 계승 할 클래스 LXFWeak Target 을 만 들 고 타 이 머 를 만 드 는 방법 을 제공 합 니 다.

#import <Foundation/Foundation.h>
@interface LXFWeakTarget : NSObject
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
@end

#import "LXFWeakTarget.h"

@interface LXFWeakTarget()
@property(nonatomic, weak) id target;
@property(nonatomic, assign) SEL selector;
@end

@implementation LXFWeakTarget
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo {
  //         
  LXFWeakTarget *object = [[LXFWeakTarget alloc] init];
  object.target = aTarget;
  object.selector = aSelector;

  return [NSTimer scheduledTimerWithTimeInterval:ti target:object selector:@selector(execute:) userInfo:userInfo repeats:yesOrNo];
}
- (void)execute:(id)obj {
  [self.target performSelector:self.selector withObject:obj]; 
}
@end
LXFTimerView.m 에서 LXFWeak Target 의 헤더 파일 가 져 오기

#import "LXFWeakTarget.h"
타이머 생 성 클래스 를 LXFWeak Target 으로 변경 합 니 다.

self.timer = [LXFWeakTarget scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(log) userInfo:nil repeats:YES];
이제 프로그램 을 다시 실행 해 보도 록 하 겠 습 니 다.
 
마지막 으로 사고의 방향 을 상세히 밝히다.
  • 우 리 는 LXF Weak Target 으로 LXFTimer View 를 대신 해서 약간의 조작 을 수행 합 니 다
  • 타이머 에 강하 게 인용 되 지 않 은 LXFTimer View 가 부모 컨트롤 에서 제거 되면 dealloc 방법 이 실행 되 고 LXFTimer View 가 삭 제 됩 니 다
  • 타 이 머 를 폐기 하고 nil 로 설정 하면 타 이 머 는 LXF Weak Target 에 대한 인용 도 없고 LXF Weak Target 도 소 멸 됩 니 다
  • 자,그럼'왜 LXFTimer View 의 timer 속성 은 weak 로 해 야 합 니까?'라 는 문 제 는 더 이상 해석 할 필요 가 없 겠 죠?
    이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기