Swift高级分享 - 在Swift中改变范式

每年WWDC期间,我们都会向Apple开发人员社区提供一整套新工具,API和技术,我们可以使用它们来进一步改进我们的应用程序及其运行的系统。虽然这些变化中的大多数往往是非常缓慢和稳定的 - 这是一种长期发生的自然演变 - 今年,情况有所不同。

SwiftUI(Apple的新声明式UI框架),Catalyst(在Mac上运行的iOS应用程序)和Combine(内置的“Rx-like”反应数据库)等技术的引入可能被认为是“苹果平台应用程序开发的新时代。这可能听起来有点夸张 - 但我认为,自从2014年推出Swift以来,苹果公司在开发者工具方面没有尝试实现这一重大飞跃。

那么这对我们第三方开发人员意味着什么呢?我们如何为未来几年经历重大范式转变做好准备- 当我们从命令式转变为声明式,从Objective-C转向Swift,从代表转向订阅者?这就是我们本周要看的内容。

同时小编这里有些书籍和面试资料哦(点击下载

逐步采用,逐步掌握

当呈现任何类型的技术转变 - 无论是从基于帧的布局到自动布局,从32位到64位应用,还是从UIKit到SwiftUI - 它都很有可能将这种转变用作重新开始的机会从一个完全干净的石板。使用旧的遗留代码,以及漂亮,闪亮的新API。

*“我们从头开始重写我们的应用程序”*是您经常听到各种规模的公司在博客文章,会议演讲,甚至面向客户的营销中自豪地宣布的事情 - 开发人员和客户都经常在听到句子时感到非常兴奋像那样。它使应用程序更新看起来像新鲜和全新的东西,而不仅仅是增量升级。

然而,虽然完全重写确实有它们的优点 - 并且如果代码库真的超出了不归路的地位可能是有理由的 - 它们在实践中的结果往往不如理论上那么吸引人,因为旧的错误被替换了通过新的错误,在编写新的实现时,错过了各种细微之处和处理边缘情况。

特别是在经历重大范式转变时,逐渐采用我们可以轻松使用刚刚引入的所有新技术,模式和工具 - 这两种方式都可以让我们继续利用现有的代码库,并让我们继续运输定期向我们的用户提供应用。

逐渐采用新技术还可让我们在完全潜入之前将脚趾浸入水中 - 让我们逐渐掌握新的API和惯例,同时开始使用它们。毕竟,在采用新工具和框架方面并没有真正的匆忙 - 它不像我们一直在运送的现有框架和代码将在一夜之间停止工作。

连连看

虽然在纸面上逐渐采用可能听起来很棒,但实际上在实践中完成它可能不那么简单。关键是要找到一种很好的方法,我们现有的代码和功能与我们引入的新代码和模式*“混合和匹配”*。

例如,当谈到像SwiftUI这样的新框架时,Apple已经考虑到了这一点,并且提供了SwiftUI和UIKit之间的完全互操作性。因此,如果我们想要开始采用SwiftUI,通过使用它构建单个屏幕 - 比如用于呈现应用内促销的视图 - 那么我们可以通过将新的SwiftUI包装PromotionView在一个实例中来实现UIHostingController,如下所示:

let vc = UIHostingController(rootView: PromotionView())

因为UIHostingController它只是一个普通的UIKit视图控制器 - 它可以作为一个孩子呈现,嵌入或推送到导航控制器 - 所有这些都是由引擎盖下的SwiftUI供电。

当框架具有明确的向后兼容性故事时,这通常是一个很好的标志 - 因为它表明作者不仅专注于构建一套新的工具,而且还关注如何将这些工具集成到现有项目中,这通常会产生更完整的API。

更好的是,新工具和框架不仅提供向后兼容性,还提供向前兼容性。再次使用SwiftUI作为示例,UIView通过将其包装在UIViewRepresentable协议的实现中,任何都可以很容易地与SwiftUI兼容。这是一个包装现有的示例ProfileView,它是UIView用于呈现用户配置文件的子类:

struct ProfileSwiftUIView: UIViewRepresentable {
    let user: User

    func makeUIView(context: Context) -> ProfileView {
        return ProfileView()
    }

    func updateUIView(_ view: ProfileView, context: Context) {
        view.nameLabel.text = user.name
        view.imageView.image = user.image
    }
}

上述两种技术都是明确的例子,说明新的开发者范例 - 如SwiftUI - 如何能够逐步实现,而不是通过完全重写,只要正确的工具已经到位。逐渐采用并不总是可行的,但是当它成熟时,它让我们都使用新技术来构建新功能 - 同时仍然充分利用我们现有的代码 - 给我们两全其美。

并行实现

由于范式转换通常发生在很长一段时间(甚至几年),因此仅仅使用新工具和API构建新功能并不总是足够的。我们可能不准备放弃对旧操作系统版本的支持,或者我们可能不完全相信某个新工具适合我们正在尝试构建的内容。

在这两种情况下,使用相同功能的多个并行实现可以是一种选择。虽然这是一个肯定会有成本的选择,但它确实给了我们额外的灵活性 - 因为我们可以开始使用新技术替换给定功能的实现细节,所有这些都不会放弃现有用户或现有代码。

让我们看看如何在实践中完成,再次使用SwiftUI作为示例。假设我们想开始尝试使用SwiftUI来构建我们的应用程序的一个功能 - 学习它,并弄清楚我们的代码库如何最好地利用它 - 同时仍然保留我们基于UIKit的实现,现在。

为此,我们可以使用工厂模式创建一个抽象,隐藏当前用于实现我们的功能的UI框架 - 在这种情况下的文章阅读屏幕:

protocol ArticleViewControllerFactory {
    func makeViewController(for article: Article) -> UIViewController
}

使用上述协议,我们现在可以轻松更改我们的功能将使用哪个UI框架,而无需更改代码库的任何其他部分。我们可以首先将我们现有的基于UIKit的工具包装ArticleViewController在一个简单地创建它的新实例的工厂中,通过传递它所需的依赖关系 - 像这样:

struct ArticleUIKitViewControllerFactory: ArticleViewControllerFactory {
    let navigator: ArticleNavigator
    let imageLoader: ImageLoader

    func makeViewController(for article: Article) -> UIViewController {
        return ArticleViewController(
            article: article,
            navigator: navigator,
            imageLoader: imageLoader
        )
    }
}

类似地,我们可以创建另一个ArticleViewControllerFactory实现,而不是创建基于SwiftUI的实例ArticleView- 然后将其包装在a中UIHostingController,然后返回。为了能够继续将我们的应用程序发送给使用iOS 12及更低版本的用户,我们还将此工厂实施标记为仅在iOS 13上可用:

@available(iOS 13, *)
struct ArticleSwiftUIViewControllerFactory: ArticleViewControllerFactory {
    let navigator: ArticleNavigator
    let imageLoader: ImageLoader

    func makeViewController(for article: Article) -> UIViewController {
        let view = ArticleView(
            navigator: navigator,
            imageLoader: imageLoader
        )

        return UIHostingController(rootView: view)
    }
}

有了上述内容,我们现在可以根据任意数量的条件选择要使用的实现 - 例如我们所针对的设备是否已经在运行iOS 13,以及我们是否启用了自定义USE_SWIFT_UI 编译器标志

let articleViewControllerFactory: ArticleViewControllerFactory = {
    #if USE_SWIFT_UI
    if #available(iOS 13, *) {
        return ArticleSwiftUIViewControllerFactory(
            navigator: navigator,
            imageLoader: imageLoader
        )
    }
    #endif

    return ArticleUIKitViewControllerFactory(
        navigator: navigator,
        imageLoader: imageLoader
    )
}()

做上面这样的事情看起来可能是很多不必要的额外工作(为什么我们只能拥有一个相同功能的两个实现?) - 但它确实给了我们一些额外的灵活性 - 以及一种开始缓和的方法进入一个新的范例(并给我们一个*“安全的地方”*来学习它的所有新模式),同时仍然能像以前一样继续发送我们现有的代码。

上述方法还可以改进代码库中的关注整体架构和分离的好方法,因为我们不得不确保我们的核心业务-像ArticleNavigatorImageLoader在这个例子-完全从我们的UI代码中分离出来,这通常使整体结构更清晰,更容易测试。

结论

大范式的转变既令人兴奋,也令人困惑,有点可怕。虽然人们常常感觉到主要的新API和技术的引入突然将我们现有的所有代码转变为*“技术债务”* - 这种情况很少发生,并且通常有一种方法可以让我们继续利用我们现有的代码代码的功能,同时也开始采用和学习新范式的技术和模式。

你怎么看?您对采用SwiftUI,Combine,Catalyst以及今年WWDC期间推出的一些其他主要新技术有何看法?你会采取逐件的方法,完全重写,或介于两者之间 - 并且本文中介绍的任何技术是否会帮助你一路走来?请通过加我们的交流群 点击此处进交流群 ,来一起交流或者发布您的问题,意见或反馈。

谢谢阅读~点个赞再走呗!?

原文地址 https://www.swiftbysundell.com/posts/shifting-paradigms-in-swift

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值