资讯专栏INFORMATION COLUMN

Swift锋芒毕露 无脑意译

APICloud / 2042人阅读

摘要:建议尽量避免无用选项关键字。在选项关键字也是这样的原理,也只有两种情况有值跟中选项与布尔同样都用枚举定义。如果你要存一个布尔或者字符串的字典,你可以使用作为值。如果我们擅自添加了一类情况,我们需要更新所有用到该类枚举类型得代码。

前言

作者自己说自己很喜欢swift,因为他喜欢Haskell。可能看上了swift支持函数式编程的缘故。

中间扯皮各种略。。。

扯到函数编程刚开始不习惯但是会带来方便。。略结束。。。

栗子

ex by oc:

- (NSAttributedString *)attributedString:(NSString *)input 
{
    return [[NSAttributedString alloc] initWithString:input];
}

看上去无公害,但是参数如果是nil,那边会导致崩溃。而且更坑爹是在运行时才会发现这个问题。这种问题一旦是你的下游程序猿(用户)去接手的时候,找这个BUG就不是很好找了咯。

对比Swift写法:

extension NSAttributedString {
    init(string str: String)
}

如果可以传入一个nil值得参数,那么接口会变成这样:

extension NSAttributedString {
    init(string str: String?)
}

这种写法的优势在于更强的解释性,也省去了看文档的时间。更不会导致运行时错误。

建议

尽量避免无用选项关键字。用选项关键字是确实需要才使用的,比如你的参数是颜色,颜色需要符合某种要求。如果此时你的参数不满足这种要求那么你希望返回nil:

func parseColorFromHexString(input: String) -> UIColor? {
    // ...
}
枚举

枚举是swift得新特性,与OC的枚举有显著的不同。OC中的枚举说白了就是整型。

让我们考虑下布尔类型。我们只需要考虑真或假。
在选项关键字也是这样的原理,也只有两种情况:有值跟nil.swift中选项与布尔同样都用枚举定义。不同的是选项枚举是带绑定值得。我们来看下各自的定义:

enum Boolean {
    case False
    case True
}

enum Optional {
    case Nil
    case Some(A)
}

二选一枚举经常在函数式编程中用于你在两件事物中进行选择的场景。举个栗子,如果你想返回一个整型或者错误,你可以使用Either。如果你要存一个布尔或者字符串的字典,你可以使用Either作为Key值。

清楚的知道什么时候该用枚举什么时候不该用枚举有一点难度,当我们为一组相近类型得数据创建结构的时候。栗子,如果我们用swift来封装Github的接口,我们需要把各种暴露出的接口用枚举型来表示。为了获得用户头像,我们提供用户名。获取用户版本库我们提供了用户名跟,排序布尔值。

enum Github {
    case Zen
    case UserProfile(String)
    case Repositories(username: String, sortAscending: Bool)
}

定义开发性接口使用枚举真是棒极了。接口列表是受限的,我们可以定义各类接口。如果遗漏了某个枚举值我们会接受到一个告警。如果我们擅自添加了一类情况,我们需要更新所有用到该类枚举类型得代码。

其他使用枚举的时候不能随意添加case,除非有代码权限。这是一个非常好的限制。假想下你可以添加一个情形到Bool或者Optional,那么你所有用来它得方程都得重写。

让我们拿货币转换器做个栗子:

enum Currency {
    case Eur
    case Usd
}

这样我们可以根据货币字符串来获取货币符号:

func symbol(input: Currency) -> String {
    switch input {
        case .Eur: return "€"
        case .Usd: return "$"
    }
}

func format(amount: Double, currency: Currency) -> String {
    let formatter = NSNumberFormatter()
    formatter.numberStyle = .CurrencyStyle
    formatter.currencySymbol = symbol(currency)
    return formatter.stringFromNumber(amount)
}

在swift不能简单去继承父类来扩展枚举类型。需要通过用协议来实现枚举的扩展。

protocol CurrencySymbol {
    func symbol() -> String
}

现在,我们可以让Currency成为协议的一个实例,现在我们可以将input参数剔除,因为默认传入self

extension Currency : CurrencySymbol {
   func symbol() -> String {
        switch self {
            case .Eur: return "€"
            case .Usd: return "$"
        }
    }
}

重写format

func format(amount: Double, currency: CurrencySymbol) -> String {
    let formatter = NSNumberFormatter()
    formatter.numberStyle = .CurrencyStyle
    formatter.currencySymbol = currency.symbol()
    return formatter.stringFromNumber(amount)
}

现在我们可以通过让各种各样的数据类型来遵循这个协议的方式让我们的代码具有灵活的扩展性,比如现在有比特币类型:

struct Bitcoin : CurrencySymbol {
    func symbol() -> String {
        return "B⃦"
    }
}

现在通过协议而并非具体类的方式来应对各种数据类型参数值得方式可以使我们的代码更易于扩展。你可以使用便利的扩展搭配使用协议,你的代码将更具语言表达力!请根据你的实际情况决定你的忌口是开放还是封闭!

类型安全

swift还有一个优势在于它的类型(数据)安全,正如前面说到的optionals。我们可以将类型检查从运行时提到编译时通过一些技巧。举个数组的栗子,数组是泛型的,它可以容纳同一类型的元素。不可以在字符串数组内添加整型。(当然你可以通过Either来弄出一个混合数组。。 - -||)

又假设我们要将currency converter变成一个通用的转换器。如果我们用Double来表示总数,这样会导致一定的混淆。举个栗子,100.0可能意味着100美元,100千克,或者其他代表100的东东。我们要做的是让类型系统来为我们根据物理量创建出相对应得数据类型。举个栗子,我们可以定义这样的一个类型来描述货币:

struct Money {
    let amount : Double
    let currency: Currency
}

同样,我们可以定义质量的数据结构:

struct Mass {
    let kilograms: Double
}

这样可以增加代码的可读性,假设我们有如下重量方程的接口:

func pounds(input: Double) -> Double

这样显然太晦涩了,我们可以这么写:

func pounds(input: Mass) -> Double

这样写的好处有二,其一是代码解释性强了,第二编译器会帮我们进行类型检查。

不可变

另一个swift支持的特性是内置支持值不可变。在Cocoa框架里面有很多API的参数设置为不可变额。还有成双出现得一些类表达可变不可变(NSString vs. NSMutableString, NSArray vs. NSMutableArray)。在swift中就简单明了多了:
var修饰的变量可变而let修饰的变量不可变。好处是接口更具有表达性以及涉及多线程操作更为容易。

总结

令作者倍感欣慰的是编译器做了原来我们读文档需要的活儿。然后也预测了下未来。。。略。。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/15507.html

相关文章

  • 设计优雅的移动端游戏 无脑意译

    摘要:前言的前言终于推出了游戏相关期刊。我们怎么设计出一款不错的游戏呢关卡长度以及交互方式。为了更好的根据实际情形进行游戏设计,我们通常把一款游戏项城市一个反馈循环。在游戏中的任一时刻,可以拥有任意数量的内嵌反馈循环。 前言的前言 OBJCIO终于推出了游戏相关期刊。我能说我想转行吗。。。不过在IT行业貌似去哪里都是要被虐。。。我还是安安静静的做个美男子吧。。 前言 扯皮游戏现状、局限...

    Cheng_Gang 评论0 收藏0
  • 视图控制器容器 无脑意译

    摘要:前言以前控制器容器是苹果专用呵呵,苹果一直都狠。两个子控制器视图添加到容器视图内是为了保证翻转动画不引起整个根视图的翻转。通信视图控制器需要满足可以服用并且是自包含的实体,子视图控制器也不例外。 前言 ios5以前控制器容器是苹果专用(呵呵,苹果一直都狠XD)。使用控制器容器的视图层级如下:showImg(https://segmentfault.com/img/bVdkYs); ...

    cooxer 评论0 收藏0
  • 构建流程 无脑意译

    摘要:控制构建流程下图应该很熟悉了。。。自定义构建阶段另外一个非常棒的用途是可以水印你的带上版本号以及提交哈希值。你可以添加构建阶段以此来枷锁你的版本号和版本哈希值甚至你可以强迫自己或者你同事来遵守代码规范,比如一个文件代码不能超过行。。。 学会看懂构建日志 选择报告导航栏下的Build选项可以查看构建日志。 工程之间有一些依赖关系,例如Pods又例如子工程。 举个栗子 拿objcio...

    mingde 评论0 收藏0
  • 轻量级视图控制器 无脑意译

    摘要:通常,将这些状态放到一个独立的对象,并将这个对象传给视图控制器通过这样可以来观察这个状态。总结编写高度解耦简洁可维护的视图控制器 前言 总的来说试图控制器是代码最多的文件并且大多都是不可复用的代码。下面将教你做到文件瘦身、代码复用、合理代码分配。 分离数据源与协议类 一句话就是将UITableViewDataSource部分的代码单独写成一个类,通过继承它达到重用。 栗子,这里有...

    CloudDeveloper 评论0 收藏0
  • 什么是动画 无脑意译

    摘要:否则动画如下时间源函数在现实生活中是需要加速以及减速后进入匀速状态,动画需要尽量的真实需要引入时间参数方程来描述加速与减速的过程。代码如下注贝塞尔曲线是用来画平滑曲线用的。。。同时我们可以用组动画在同一时刻进行时间源函数控制。 前言 应用中的动画根据需求肯定不可能是一成不变的。 当动画进行不同的状态切换的时候我们需要接下来要做什么。与见见单单的两个屏幕画面跳转不同,动画需要告诉用户...

    Rango 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<