關于拆分View層的一種優化實戰

今天給大家提供一種在iOS開發中View層的一種優化思路。

在iOS開發中,不管你是用純代碼布局,還是用Storyboard布局,都免不了在Controller中加入一些界面相關的邏輯,隨著業務邏輯復雜度的增加,Controller里的代碼會越來越多,不方便閱讀,還不方便維護,這時候除了把一些業務邏輯分出去之外,還可以把界面相關的代碼優化一把。

優化主要借助Controller中的loadView來實現,對于這個方法,官方文檔里描述的很清楚,這里不再過多描述。我們主要是在loadView中把我們自己定義的View賦給Controller的view屬性,然后把所有界面相關的代碼都在我們自己定義的View中去管理。

畫板.png

這里我使用App的登錄注冊功能做簡單分析,界面如上圖所示,圖一是登錄界面,圖二是注冊界面,其中圖一的布局是用Storyoard做的,圖二是用純代碼配合Masonry寫的,先說圖二純代碼寫的吧,首先我們需要寫一個RegistView,相關代碼如下:

@interface RegistView : UIView

@property (nonatomic, strong) UITextField *userNameTextField;
@property (nonatomic, strong) UITextField *userPswdTextField;
@property (nonatomic, strong) UITextField *againPswdTextField;
@property (nonatomic, strong) UIButton *registButton;

@property (nonatomic, copy) void (^registCallBack)(NSString *, NSString *, NSString *);

@end

@implementation RegistView

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        [self loadSubviews];
    }
    return self;
}

- (void)loadSubviews {
    self.backgroundColor = [UIColor whiteColor];
    [self addSubview:self.userNameTextField];
    [self addSubview:self.userPswdTextField];
    [self addSubview:self.againPswdTextField];
    [self addSubview:self.registButton];
    
    [self.userNameTextField mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.mas_left).offset(58);
        make.right.equalTo(self.mas_right).offset(-58);
        make.top.equalTo(self.mas_safeAreaLayoutGuideTop).offset(49);
        make.height.mas_equalTo(34);
    }];
    
    [self.userPswdTextField mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.equalTo(self.userNameTextField);
        make.top.equalTo(self.userNameTextField.mas_bottom).offset(22);
        make.height.mas_equalTo(34);
    }];
    
    [self.againPswdTextField mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.equalTo(self.userNameTextField);
        make.top.equalTo(self.userPswdTextField.mas_bottom).offset(22);
        make.height.mas_equalTo(34);
    }];
    
    [self.registButton mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.equalTo(self.userNameTextField);
        make.top.equalTo(self.againPswdTextField.mas_bottom).offset(22);
        make.height.mas_equalTo(50);
    }];
}

#pragma mark - Action

- (void)registAction {
    if (self.registCallBack) {
        self.registCallBack(self.userNameTextField.text, self.userPswdTextField.text, self.againPswdTextField.text);
    }
}

#pragma mark - Get

- (UITextField *)userNameTextField {
    if (!_userNameTextField) {
        _userNameTextField = [UITextField new];
        _userNameTextField.borderStyle = UITextBorderStyleRoundedRect;
        _userNameTextField.placeholder = @"點擊輸入用戶名";
    }
    return _userNameTextField;
}

- (UITextField *)userPswdTextField {
    if (!_userPswdTextField) {
        _userPswdTextField = [UITextField new];
        _userPswdTextField.borderStyle = UITextBorderStyleRoundedRect;
        _userPswdTextField.placeholder = @"點擊輸入密碼";
        _userPswdTextField.secureTextEntry = YES;
    }
    return _userPswdTextField;
}

- (UITextField *)againPswdTextField {
    if (!_againPswdTextField) {
        _againPswdTextField = [UITextField new];
        _againPswdTextField.borderStyle = UITextBorderStyleRoundedRect;
        _againPswdTextField.placeholder = @"點擊再次輸入密碼";
        _againPswdTextField.secureTextEntry = YES;
    }
    return _againPswdTextField;
}

- (UIButton *)registButton {
    if (!_registButton) {
        _registButton = [UIButton buttonWithType:UIButtonTypeSystem];
        [_registButton setTitle:@"注冊" forState:UIControlStateNormal];
        [_registButton addTarget:self action:@selector(registAction) forControlEvents:UIControlEventTouchUpInside];
        
    }
    return _registButton;
}

其次是在Controller里面loadView方法里面給view屬性賦值,代碼如下:

@interface RegistViewController ()

@property (nonatomic, strong) RegistView *mainView;

@end

@implementation RegistViewController

- (void)loadView {
    self.mainView = [[RegistView alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.view = self.mainView;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self configViews];
}

- (void)dealloc {
    NSLog(@"%s", __func__);
}

#pragma mark -

- (void)configViews {
    self.title = @"注冊";
    __weak typeof(self) weakSelf = self;
    self.mainView.registCallBack = ^(NSString * _Nonnull userName, NSString * _Nonnull userPswd, NSString * _Nonnull userAgainPswd) {
        if (nil != weakSelf) {
            
        }
        NSLog(@"%@ %@ %@", userName, userPswd, userAgainPswd);
    };
}


@end

這樣我們就順利的把Controller里面對關于View的東西都優雅的拿出來了。

如果你是Storyboard愛好者,同樣的也有辦法去處理,以圖一為例,首先我們要在Storyboard里面完成LoginView的布局,如圖:
WX20191222-161005@2x.png

其中我們把Storyboard中Controller的view關聯到了我們本地創建的LoginView上,對相應的一些空間也做了關聯,相關代碼如下:


@interface LoginView : UIView
@property (weak, nonatomic) IBOutlet UITextField *userNameTextField;
@property (weak, nonatomic) IBOutlet UITextField *userPswdTextField;
@property (weak, nonatomic) IBOutlet UIButton *loginButton;
@property (weak, nonatomic) IBOutlet UIButton *registButton;


@end

@implementation LoginView

-(void)awakeFromNib {
    [super awakeFromNib];
    NSLog(@"%s", __func__);
    // TODO: 操作一些樣式相關、狀態相關的
}
@end

而在Controller里面我們需要對view做一個類型轉換,然后才能使用,相關代碼如下:

@interface LoginViewController ()

@property (nonatomic, weak) LoginView *mainView;

@end

@implementation LoginViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.title = @"登錄";
}

#pragma mark - Action

- (IBAction)loginAction:(id)sender {
    NSString *userName = self.mainView.userNameTextField.text;
    NSString *userPswd = self.mainView.userPswdTextField.text;
    
    NSLog(@"%@ %@", userName, userPswd);
    
    // TODO: 處理登錄的邏輯
}

- (IBAction)registAction:(id)sender {
    RegistViewController *vc = [RegistViewController new];
    [self.navigationController pushViewController:vc animated:YES];
}


#pragma mark - View

- (LoginView *)mainView {
    return (LoginView *)self.view;
}


@end

這樣,我們就優雅的完成了對View層的拆分。點擊下載demo

如果大家有什么問題,或者發現了有什么不對的地方,再或者有更好的方法,歡迎留言。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容