iOS ViewController가 get 방법을 이용하여view를 만드는 위험

4491 단어
일상적인 iOS 개발 과정에서 ViewController를 만들고 get을 다시 쓰는 방법으로 보기를 만들어서 viewDidLoad 방법의 코드를 더욱 간결하고 조리가 있어 보인다.그러나 실제로 이런 방법은 위험이 존재한다. 아래의 코드 예를 보면 다음과 같다.
// MyViewController.h
@interface MyViewController : UIViewController
- (void)setLabelText:(NSString *)text;
@end
// MyViewController.m
#import "MyViewController.h"

@interface MyViewController ()
@property (nonatomic, strong) UILabel *label;
@end

@implementation MyViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor orangeColor];
    [self.view addSubview:self.label];
}

- (void)setLabelText:(NSString *)text {
    self.label.text = text;
}

- (UILabel *)label {
    if (!_label) {
        _label = [[UILabel alloc] initWithFrame:self.view.bounds];
        _label.backgroundColor = [UIColor redColor];
    }
    return _label;
}
@end
// ParentViewController.h
@interface ParentViewController : UIViewController
@end
// ParentViewController.m 
#import "ParentViewController.h"
#import "MyViewController.h"

@interface ParentViewController ()

@end

@implementation ParentViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    MyViewController *vc = [[MyViewController alloc] init];
    [vc setLabelText:@"123"];
    [self.view addSubview:vc.view];
    [self addChildViewController:vc];
    [vc didMoveToParentViewController:self];
}

위에서 보듯이 현재 2개의 controller: ParentViewControllerMyViewController을 정의했다.이 중 MyViewController은 하위 컨트롤러로 ParentViewController에 나타났다.MyViewController, get 방법을 다시 써서 전체 화면의 label을 만들고 문서를 표시합니다.
현재 ParentViewController을 만들고push를 표시합니다. 코드는 다음과 같습니다.
- (void)gotoNext {
    ParentViewController *vc = [[ParentViewController alloc] init];
    [self.navigationController pushViewController:vc animated:YES];
}

이 주요 코드가 모두 완성되었습니다. 프로그램이 실현하고자 하는 기능: 새push에 나온 페이지에 빨간색 label이 표시되며, 문안은 123입니다.
이 프로그램이 우리가 원하는 기능을 실현할 수 있는지 분석해 봅시다.만약 안 된다면, 인터페이스는 어떤 것을 보여줍니까?
답안: 기능을 실현할 수 없습니다. 인터페이스에 표시된 label의 배경색(빨간색)이 있지만 문안이 없습니다.
이유는 다음과 같습니다.[vc setLabelText:@"123"]을 호출하여 self.label.text = text;을 실행하고 label 속성의 get 방법을 터치하여 label 창설의 논리에 들어가면 _label = [[UILabel alloc] initWithFrame:self.view.bounds]; 이 줄 코드를 호출하는 실행 순서는 [UILabel alloc] -> self.view.bounds -> initWithFrame: ->label 변수에 값을 부여합니다.self.view.bounds까지 실행되었을 때 컨트롤러의view가 만들어지지 않았기 때문에 self.view은 컨트롤러의 loadViewviewDidLoad 등 관련 방법을 촉발한다.viewDidLoad 방법에서 [self.view addSubview:self.label];에 label 속성을 다시 터치하는 get 방법을 호출합니다.이 호출 창고는self이기 때문입니다.view->viewDidLoad->get 방법, 그래서 위에서 언급한 _label = [[UILabel alloc] initWithFrame:self.view.bounds] 코드는 initWithFrame: 방법을 실행하지 않았고 완성하지 않았습니다label의 값 부여 작업이기 때문에 여기에서 호출한 get 방법은 if (!_label) 문장을 통해 label의 실례를 다시 만들고 이 실례를 되돌려줍니다. 이 실례는dd에 의해 controller에 연결됩니다.view에서 이viewDidLoad가 실행되었습니다.self로 돌아갑니다.view, self.view.bounds 계속 실행 -> initWithFrame: ->label 변수에 값을 부여합니다.
여기까지 거의 분석이 끝났습니다. 위에서 언급한 바와 같이 프로그램 뒤에 또label 변수는 새로운 실례를 부여하여 self.label.text = text; 이때self로 되돌려줍니다.label은 새로운 실례, 이 실례와 controller를 가리킨다.view에 붙인 label은 다른 두 가지 실례입니다.그래서 셀프한테.label 값 부여 문자는 아무런 작용이 없습니다. 왜냐하면 이 label은 전혀 나타나지 않았기 때문입니다.다른 상관없는 label이 표시됩니다.

总结


문제는 controller의 보기가 만들어지지 않았고 get 방법에서self가 사용되었습니다.view,viewDidLoad의 호출 시기가 혼란스러웠습니다.
그래서 다음과 같은 몇 가지 개법이 있다.
  • get 방법으로 프레임을 설정할 때 가능한 self를 사용하지 마십시오.view.
  • get 방법을 다시 쓰지 마십시오.

  • 첫 번째 개법의 폐단: 만약 보기가self에 의존한다면.view, 사용할 수 없습니다.여기서 제2중개법을 제창한다.
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.view.backgroundColor = [UIColor orangeColor];
        //[self.view addSubview:self.label];
        [self.view addSubview:[self setupLabel]];
    }
    
    - (void)setLabelText:(NSString *)text {
        self.label.text = text;
    }
    
    //- (UILabel *)label {
    - (UILabel *)setupLabel {
        if (!_label) {
            _label = [[UILabel alloc] initWithFrame:self.view.bounds];
            _label.backgroundColor = [UIColor redColor];
        }
        return _label;
    }
    

    실제로는 방법명만 바꾸고 아무런 변동도 필요 없이 실현하면 된다.
    마지막으로 예시 코드의 데모를 첨부합니다

    좋은 웹페이지 즐겨찾기