(WWDC) 高级iOS应用程序架构和模式

2019-06-05  本文已影响0人  FicowShen

内容概览




前言

大多数大型应用的架构都会经历从简单到复杂的过程。

随着业务逻辑不断增多,应用需要处理的任务也会越来越繁杂,各种bug也会显现出来。
如果应用没有采用合适的软件架构和模式,问题将变得更加棘手。

你对此是否深有体会?

简单架构 规模逐步扩大的简单架构 不合理的简单架构 不合理的复杂架构 不合理的复杂架构导致的问题开始突显 在不合理的架构上进行单元测试 单元测试成为了新的麻烦




针对这些问题,我们需要对架构进行不断地探索,因此我们对架构的理解也会更加深入。
渐渐地,我们对架构的要求会越来越高。然而,往往我们的能力没有和我们的品位一起提升。


架构不是教条主义,它需要我们的洞察力!




设计信息流

混乱的信息流 清晰直观的信息流




真实数据 和 派生数据



派生数据的特点:




示例:

这是一个很常见的需求。
在界面放置一个UITextView,旁边有一个UILabel作为UITextView的文字计数器。
当UITextView的文本发生变化时,我们会在代理方法中更新UILabel的character count。



如果通过代码来直接更新UITextView的文本,是不会有代理方法被调用的。
这时候可能会出现什么问题?



如果,此时只是通过代码来更新UITextView的文本,character count将得不到更新:



所以,我们需要通过model来直接更新TextView的文本和character count,因为实际的数据在model处。



如果用户输入了新的值,model也需要被更新。



但是,如果只是这样做的话,我们就丢失了原始数据。
假如,当前页面是主界面列表中某一条记录的详情页,用户通过点击主界面列表跳转到当前页面。如果我们直接对原始的模型进行修改,这是不合理的。



所以,合理的设计应该是这样的:



总结一下设计信息流的过程:




定义明确的责任

职责不明确 职责明确



对输入数据进行校验是软件开发中常见的情况,尤其是对注册、登录模块的输入数据进行校验。



常见的验证流程:



全部输入框的验证流程:



某个输入框的验证流程:



在这个过程中,我们还需要判定nil:




然后,我们可能会写出这样的代码:

NSString *username = [self.usernameField text];
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@“[a-zA-Z0-9_]{6,}” options:0 error:nil];
NSRange result = [regex rangeOfFirstMatchInString:username options:NSMatchingAnchored range:NSMakeRange(0, [username length])];
if (username && result.location == NSNotFound) {
   allValid = NO;
   [self.usernameField setBackgroundColor:[UIColor redColor]];
} else {
   if (!username) {
      anyNil = YES;
   }
   [self.usernameField setBackgroundColor:[UIColor whiteColor]]];
}

请注意,验证过程直接对输入框的背景色进行了更改,这是不合理的。

而且,验证过程被定义在了ViewController中,这也是不合理的。



如果有多个页面需要进行相同的校验,一定会出现这样的情况:



所以,我们应该将验证过程独立出来:



验证过程的特征:



根据以上特征,定义一个验证器协议:

protocol Validator {
    validateWithError(error: NSErrorPointer) -> Bool
}



这样定义有以下优势:



然后,定义用户名验证器:

class UsernameValidator: Validator {
  var input: NSString?
  func validateWithError(error: NSErrorPointer) -> Bool {
    let regex = NSRegularExpression(pattern: ...)
    ...
  }
}

然后,定义密码验证器:

class PasswordValidator: Validator {
    var input: NSString?
    ...
}

class SetPasswordValidator: Validator {
    let firstPasswordValidator = PasswordValidator()
    let secondPasswordValidator = PasswordValidator()
    ...
}

然后,只需要组合前面的验证器就可以轻松定义注册验证器:

class SignUpValidator: Validator {
    let usernameValidator = UsernameValidator()
    let setPasswordValidator = SetPasswordValidator()
    let emailAddressValidator = EmailAddressValidator() 
    ...
}




用不变性进行简化

假设有三个实例 A, B, C:

当你需要把A中的值赋给B时,如果这个值为引用类型,那么A仍然指向了这个值。

如果,B对这个值进行修改,A也会受到影响。

如果再将这个引用值赋给C,情况将会变得更加复杂。




如果使用值类型,而不是引用类型呢?

把A中的值赋给B。


B如果改变这个值也不会影响A。





Swift中的 struct 是很好用的值类型,它有以下特征:




参考内容:
Advanced iOS Application Architecture and Patterns




转载请注明出处,谢谢~

上一篇下一篇

猜你喜欢

热点阅读