Flutter有局限,拥抱Swift!优酷Mac迁移Swift实践

发表于 4年以前  | 总阅读数:1606 次

Flutter有局限,拥抱Swift!优酷Mac迁移Swift实践

不管从“明里”还是“暗里”来看,苹果都在大力推荐使用 Swift 这一门语言。作为苹果的“亲儿子”,相信 Swift 语言将会是开发 MacOS 和 iOS 的第一选择。  一、背景 随着 Swift 5.0 的发布,Swift 的 ABI 终于稳定下来了。如果是很早就拥抱 Swift 的开发者,一定经历过各 Swift 大版本发布时的痛苦。回想在前一家公司将 Swift 2.2 升级到 Swift 3.0,基本上是换了个语言,两个版本之间的差异非常之大,升级起来简直是苦不堪言。

另外 ABI 的稳定也让 Swift 运行时环境可以随着苹果系统(iOS, Mac OS, Watch OS, TV OS)一起发布,不用再将 Swift 加入应用包,减小了包的体积。

所以,如果以前不使用 Swift 的原因之一,是 Swift 不稳定造成的开发成本过大,那随着 Swift 5.0 的发布,终于可以抛开这个顾虑了。

二、为什么迁移 Swift

当然,仅仅就 ABI 稳定这一个原因,肯定不足以说服我们将 Objective-C(以下简称 OC)迁移到 Swift,我们还得看看使用 Swift 能够给我们带来什么东西是 OC 没有的。

安全编程

Swift 是一门静态语言,虽然没有 OC 动态特性的灵活,但是这也让 Swift 更加安全。当然,静态语言非常多,为何 Swift 会特意强调“安全”这一特性?因为 Swift 在语言层面做了很多工作。

  1. 可选值。可选值的引入明确了这样一个问题:这个值是否存在。这使得我们在处理某个值的时候,能够很清楚的知道是否应该去判断这个值的有无,避免了不必要的 crash 问题;

  2. 值类型。Swift 中的 Struct 是一个值类型,它和引用类型的最大区别就是,将一个值类型赋给另外一个变量时,是通过值拷贝完成的(当然 Swift 用了 Copy-on-Write 的技术保证性能),我们就不用担心拷贝之后使用的安全问题,不用担心新变量的值修改之后会影响到原来的值;

  3. 更多安全的关键字。guard让我们在执行接下来的代码前保证某一个条件的成立,并且使程序可读性更高;defer避免我们忘记在代码块执行完毕后所需要执行的清理工作。

编程范式的丰富

  1. 支持函数式编程。函数作为 Swift 中的一等公民,Swift 可以支持函数式编程。我们可以使用函数式编程的无状态性,不可变性,无副作用这些特性写出更健壮的代码;

  2. 面向协议编程。Swift 中也有协议 protocol,不过 Swift 中的 protocol 比起 OC 中的 protocol 强大太多。我们可以扩展协议给协议中的方法给一个默认实现。这样我们就可以在不改动已有类或 Struct 的前提下添加能力,非常的方便;

  3. 强大泛型。泛型的引入可以让我们编写一些更加通用的代码,使代码更加灵活,可用性更高。

其它

如没有头文件减轻了复杂性,让代码量更少;利用元组(tuple)支持多返回值减少了一些不必要的模型等等。这些都使代码更简洁,更清晰。

三、迁移实战从哪里开始迁移?

Swift 和 OC 可以相互调用,但是由于 Swift 新增了一些新的数据结构,如 Enum、 Struct 等,因此 OC 调用 Swift 时有一定的局限性,需要做的一些额外的工作。反过来,当 Swift 调用 OC 时则容易得多。

一般来说,大多数 iOS 工程都有如下结构:

从上图可以看出,UI View Controller 和 UI View 都是在最上层,很少有其它模块依赖它们。即使有,也是其它模块的 UI View Controller 或 UI View 对其有依赖。因此,我们在迁移的时候可以从 UI View Controller 和 UI View 相关类进行迁移。这样的话,将这些类迁移为 Swift 后,可以顺利的调用 OC 相关的类和 API。

另外,从稳定性的角度来看,从上到下的迁移也更安全。如果我们从下层的一些中间件或基础库开始迁移的话,由于上层的大多数业务模块都对中间件或者基础库有依赖,我们对下层模块的修改就会影响多个业务模块,而且通常不知道这些下层模块到底被上层的哪些模块所调用。如果修改出现问题就会影响到非常多的模块,更糟的是,如果是一些使用频率比较少的业务场景对这些下层模块有依赖,那么可能在开发过程中很难发现问题,不知不觉的就带到线上,造成比较大的影响。

因此,如需要将 OC 迁移到 Swift,建议按照“从上到下”的原则进行迁移。这样既保证了工作量不会太大(不用去写一些 OC 调用 Swift 的适配代码)也保证了迁移后的稳定性,测试只需回归一下迁移过的业务模块即可,还可以快速定位问题。 如何使用 Swift 的值类型 我们都知道 Swift 引入了两个重要的数据结构 Struct 和 Enum,这两个都是值类型。值类型我们都知道是非常安全的,例如下面这段代码:

var a = 1
var b = a
b = 2

我们可以随意更改 b 的值而不用担心 a 的值会受任何影响,因为值类型的赋值都是通过拷贝来进行的(并使用 Copy-on-Write 的技术来保证性能)。另外,值类型相较于引用类型来说,减少了堆上的内存分配和回收次数。理论上来说,如果能用 Struct 类型就尽量使用 Struct 类型。

@interface Video: NSObject

@property (nonatomic, copy) NSString *videoId;
@property (nonatomic, copy) NSString *videoTitle;
@property (nonatomic, copy) NSString *videoSubtitle;

@end

例如我们有一个 Model 叫 Video,然后我们用 Struct 可以写成这样:

struct Video {
    let videoId: String
    let videoTitle: String
    let videoSubtitle: String
}

这样改写不仅将我们的 Model 改成更加安全的值类型 Struct,还利用了 let 关键字将里面的属性改为不可变的,使代码更加安全。

哪些又需要改成 Enum 类型呢?Enum 类型特别适合那种有明显种类区别的场景。例如以下代码:

typedef NS_ENUM(NSUInteger, TradeType) {
    TradeTypeVip = 0,
    TradeTypeSingleVideo
};


@interface TradeManager: NSObject

- (void)buyWithType:(TradeType)type;

@end

比如我们的支付场景分为购买 VIP 会员 ,购买单片。在 OC 中我们会定义一个 enum 来区分不同的购买类型,然后通过TradeManager相关 API 来进行购买。

[[TradeManager sharedManager] buyWithType:TradeTypeVip]

而在 Swift 中我们可以把它改成这样:

enum Trade {
    case VIP(userId: String)
    case singleVideo(videoID: String)

    func buy() {
        switch self {
        case .VIP(let userId):
            // buy vip with user Id

        case .singleVideo(let videoId):
            // buy single video with video id
        }
    }
}

我们把购买的逻辑全部放到 enum 中,利用 enum 的关联值来进行相关参数的传递,而且 Swift 中的 enum 类型可以添加方法,所以我们可以把购买的业务逻辑都放到一起,通过 switch 来进行判断。

然后我们就可以这样使用:

Trade.VIP(userId: "349951").buy()

非常的简洁明了。

混编问题

虽然我们可以按照“从上到下”的原则开始迁移,但是即使是这样也免不了需要 OC 去调用 Swift 的代码,有一些地方还是得处理一下。

我们都知道,OC 是一门动态语言,所有对象都是基于运行时的。而 Swift 则是一门静态语言,除了某一些特性可能需要在运行时完成(如反射),绝大部分的工作都是在编译时就确定了的(例如 Swift 类型的成员变量或方法)。我们来看一段代码:

// method in OC file
- (void)someMethod {
    A *a = [A new];
    [a doWork];
}

// class in A.swift
class A: NSObject {
    func doWork() {
        // do something
    }
}

上面的代码中,能编译通过吗?

当然不能,因为 Swift 的类型缺少一些运行时所需要信息,会导致失败,编译器会报出No visible @interface for 'CMSFilterViewController' declares the selector ‘reloadWith:channelName:'的错误。解决方法也很简单,在所需要使用到的前添加@objc即可。

需要注意的是,Swift 的 class 类型必须继承 NSObject 才能被 OC 所调用。

// class in A.swift
class A: NSObject {
    @objc func doWork() {
        // do something
    }
}

这样,OC 就能够找到 Swift 类型中相应的方法 (属性同理)。

必须说明的一点是,标记为 @objc 并不意味着这个方法就是动态派发的,它依然是静态调用。如果想要运行时相关的特性,必须使用 dynamic 关键字,这里不再赘述。 在 Swift 那些消失的东西 在迁移到 Swift 的过程中,我们会发现某些代码并不能在 Swift 中找到对应类或者方法来处理,下面是一些典型的例子。  1) @synchronized 在性能要求不是太高的情况下,我们通常会使用@synchronized来为一个对象加上锁,而 Swift 已经没有相关的关键字了,所以我们需要做一些额外的工作。

@synchronized本质上来讲是一个互斥锁,背后其实是调用了 objc_sync_enterobjc_sync_exit 方法来实现的,所以,我们可以自己写一个类似的方法:

func synchronized(_ lock: AnyObject, block: () -> Void) { 
 objc_sync_enter(lock)
 block()
 objc_sync_exit(lock)
}

在使用时我们利用 Swift 的 Trailing Closure 可以写出类似 OC 的代码,非常的优美:

func addObject(obj: AnyObject) {
 synchronized(self) { 
  // do something
 }
}

 2) 单例

在 OC 中,我们的单例基本都是这样写的:

+ (instancetype)sharedInstance {
    static id sharedInstance = nil;
    static dispatch_once_t onceToken = 0;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

而在 Swift 中,我们直接定义一个静态常量就可以定义一个单例:

static let shared = YourObject()

不仅代码量更少,意义也更加明确。  3) dispatch_once 就像上面 OC 代码那样,一般是使用 dispatch_once 来实现一个单例。但是 Swift 中已经没有 dispatch_once 这个方法了,那如果非要要使用的话应该怎么办呢?我们可以这样定义:

public extension DispatchQueue {

    private static var _onceTokens = [String]()

    public class func once(token: String, block:()->Void) {
        objc_sync_enter(self)
        defer { objc_sync_exit(self) }

        if _onceTokens.contains(token) {
            return
        }

        _onceTokens.append(token)
        block()
    }
}

我们利用 Swift 的extension给 DispatchQueue 添加一个类方法,然后可以这样使用:

DispatchQueue.once(token: "oncetoken") {``  // do something``}

当然,OC 和 Swift 区别远远不止于此,包括 Swift 对 C 的调用,日志的打印等等都有很多可以深究的点,限于篇幅原因就不再赘述。 四、计划和展望 目前优酷 Mac 端还在继续迁移中,一方面需要进行正常的业务迭代,并不能投入太多的人力专门进行迁移,目前的做法是新的需求使用 Swift 进行开发,如果有依赖到原来 OC 的相关模块,根据工作量来进行一部分的迁移;另一方面就是考虑到项目的稳定性,也不会直接把所有 OC 代码迁移到 Swift 上,逐步迁移也方便测试人员进行针对性的回归。

Swift 所带来的肯定不只是语言层面的这些优点。WWDC 2019 年发布的 Swift UI 不仅可以使用更加简洁的语法来进行 UI 开发,最重要的是可以使用同一个 UI 组件库来开发 Mac OS 和 iOS 上的界面,让一套代码在 Mac 和 iOS 设备上运行提供了可能性。

另外,Swift 作为一个跨平台语言不只是在苹果相关的平台上运行,目前 Swift 还支持 Linux 系统,我们可以在 Linux 系统上将 Swift 作为开发语言进行开发。目前已经有跨 Android 和 iOS 的 UI 库 SCADE,可以让我们同一套代码来开发 Android 和 iOS 的界面。

可能也有人会问,跨平台现在有了 Flutter,我们还学习 Swift 干嘛呢?确实 Flutter 作为一个非常优秀的跨平台方案,它有着优秀的渲染性能,并且支持非常多的平台(iOS、Android、Mac  OS 甚至是 Windows)。但是我们也知道,Flutter 是一个 UI 组件库,它可以帮助我们解决一部分 UI 问题,但是再往下呢?还是得使用 OC 或者 Swift。有人也会说直接用 OC 不就好了。可是我们可以看到一个现象,现在苹果的官方文档上面,基本上都是使用 Swift 来编写相关的代码示例,苹果也是在慢慢的“抛弃”OC 这一门语言。

不管从“明里”还是“暗里”来看,苹果都是在大力推荐使用 Swift 这一门语言。作为苹果的“亲儿子”,相信 Swift 语言将会是开发 MacOS 和 iOS 的第一选择。

所以,如果有人问我什么时候可以开始学习 Swift,那我的答案是:现在。

作者丨阿里文娱高级无线开发工程师 大斗
来源 | InfoQ

本文由哈喽比特于4年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/yb6xBK576LS-WbOsLvRQ8Q

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
快速配置 Sign In with Apple 5年以前  |  7734次阅读
使用 GPUImage 实现一个简单相机 5年以前  |  6024次阅读
APP适配iOS11 5年以前  |  5790次阅读
 目录