介绍 Standard Library Preview Package

Apple 最近新开源了一个项目,命名为 Standard Library Preview Package,主要是用来加强 Swift Evolution 进程的。该 Preview Package 将包含已被纳入 Swift Standard Library 计划但还没被集成到 Swift 正式版中的功能。这可以使得我们在真实环境中使用这些新特性,并给予及时的反馈,同时也降低了给 Standard Library 贡献代码的技术门槛。

Preview Package 最近接收了 SE-0270 提议,该提议实现了获取一个集合的子集,比如 subranges(where:)moveSubranges(_:to:)

使用 Preview Package

想在 Swift Package Manager 项目中使用 Standard Library Preview Package,只需要编辑 Package.swift 文件即可。

let package = Package(
    name: "MyPackage",
    dependencies: [
       .package(url: "https://github.com/apple/swift-standard-library-preview.git", from: "0.0.1"),
    ],
    targets: [
        .target(
            name: "MyTarget",
            dependencies: [.product(name: "StandardLibraryPreview", package: "swift-standard-library-preview")]),
    ]
)

继续阅读“介绍 Standard Library Preview Package”

介绍 Swift Crypto 库

最近 Apple 官方推出了一个新的 SwiftSwift Crypto 。该库将 Apple 平台的 CryptoKit 库拓展到了其它平台(比如:Linux),这样其它平台上也将可以使用加密相关的 API 了。

使用方法很简单,只需要导入对应库即可:

import Crypto

示例代码

func encrypt(input: [UInt8]) throws -> Data {
    // Don't forget to save your key somewhere!
    let key = SymmetricKey(size: .bits256)
    let sealedBox = try AES.GCM.seal(input, using: key)
    return sealedBox.combined!
}

跨平台

Apple 平台上,Swift Crypto 直接使用已有的 CryptoKit 库,但其它平台上将基于 BoringSSL 库重新实现,最终将在所有平台上提供一套统一且方便使用的 API

继续阅读“介绍 Swift Crypto 库”

Swift 2019 这一年

Swift 2019 回顾

  • Swift 5 & 5.1 发布
  • Swift ABI 稳定
  • SwiftUI 发布
  • Xcode 集成 Swift Package Manager
  • SwiftNIO 2 发布
  • SwiftLog 发布
  • SwiftMetrics 发布
  • StatsdClient 发布
  • swift-numerics 发布
  • Vapor 4 Beta 发布

Swift 2020 展望

  • Swift 5.2
  • Vapor 4 正式版

继续阅读“Swift 2019 这一年”

Swift 文档编写规范

本篇为译文,原文可见:链接

如果超过 6 个月没看过自己写的代码的话,你可能会认为这些代码是其他人写的。

-Eagleson’s Law

当我们使用 Appleclass 时,如果不知道如何使用它们的话,我们有很多方式可以去查找资料。比如你可以通过 Apple Developer Documentation 在线文档或者通过 Xcode 来查找。

Quick help popover

你可以通过 ⌥ – Option + click 方式查看任何 class

Symbol inspector Quick Help

Quick help 也显示在 Quick Help 检查面板(inspector panel)上。

Code completion hint

当你开始打字时,Xcode 将会有相应的提示信息(包含 class 中的 function/property/enum

接下来将介绍如何给自己的代码加上这些提示。

Syntax

给代码写文档就像写注释一样,但是有一点点语法上的差别。你需要 /// 来标注单行的文档。

/// This is your User documentation.
struct User {
    let firstName: String
    let lastName: String
}

对于多行文档,你需要 /** ... */ 符号。

/**
    This is your User documentation.
    A very long one.
*/
struct User {
    let firstName: String
    let lastName: String
}

继续阅读“Swift 文档编写规范”

Swift Weekly 中文 – Issue #176

本篇为译文,原文可见:链接

本周的 issue ,我们主要讨论 updating the view stateanimations in SwiftUIdebugging Combine

文章

如果你正在查找关于 body 是计算型时,去尝试修改 view 状态的资料的话,这篇文章将会告诉你可以做哪些操作以及不应该做哪些操作。

Fernando Moya de Rivas 使用 SwiftUI 创建了几个有趣的动画。

学习不同方式来调试由 Swift Combine framework 编写的 functional reactive code 。通过 print()handleEvents() 来查看 console;通过 breakpointOnError()breakpoint() 来生成 Xcode 断点;以及通过绘制图表的方式。

Josh Adams 通过 SwiftUI 修改了他的一个 app,并分享了一些学习心得。

本篇文章中,Jim Dovey 解释了如何使用 SwiftUICoreData 进行绑定操作。

The folks at Just Eat have experimentation and feature flagging at their heart and they’ve developed a component, named JustTweak, to make things easier on iOS.

John Sundell 找到了一些不同的方式来添加插件支持,这样可以使得系统变得更加灵活。

介绍了如何编写 Swift 代码的文档注释。

介绍了 Alexander Grebenyuk 如何从手动测试他的框架到通过单元测试来自动化测试每一次的变更。

继续阅读“Swift Weekly 中文 – Issue #176”

Swift 之 Property Wrappers 特性

Swift 5.1 新增了 Property Wrappers 特性。该特性可以通过使用 @ 符号以注解的形式来实现某些功能,并达到简化代码的效果。

示例

iOS 中的 UserDefaults 为例,一般用法如下。

  • 存储数据
UserDefaults.standard.set(value, forKey: key)
  • 获取数据
UserDefaults.standard.object(forKey: key)

改造

Property Wrappers 需满足两个基本要求:

  • 必须使用 @propertyWrapper 关键字来修饰。
  • 必须有一个命名为 wrappedValue 的属性。

接下来以 Property Wrappers 方式改造 UserDefaults ,代码如下:

@propertyWrapper
struct MyUserDefault<T> {

    let key: String
    let defaultValue: T

    var wrappedValue: T {
        get {
            return (UserDefaults.standard.object(forKey: key) as? T) ?? defaultValue
        }
        set {
            UserDefaults.standard.set(newValue, forKey: key)
        }
    }

}

使用

@MyUserDefault(key: "username", defaultValue: "")
static var username: String

加了 MyUserDefault 自定义注解后,对 username 的赋值操作相当于是执行了 UserDefaults.standard.set 方法,对 username 的读取操作相当于执行了 UserDefaults.standard.object 方法。

限制

Property Wrappers 也有一些使用上的限制。比如:

  • 无法在 protocol 中进行声明。
  • 通过 wrapper 包装的实例属性(An instance property with a wrapper)无法在 extension 中进行声明。
  • 无法在 enum 中进行声明。
  • class 中通过 wrapper 包装的属性无法被另外一个属性通过 override 覆盖掉。
  • 通过 wrapper 包装的实例属性(An instance property with a wrapper)不能用 lazy@NSCopying@NSManagedweakunowned 来修饰。

继续阅读“Swift 之 Property Wrappers 特性”

Swift 服务端发展现状

最近 Swift Workgroup 发布了一则公告:

@IanPartridge and @Chris_Bailey let the group know that following a review by IBM of its open source priorities, it has been decided that they will not be continuing to work on Swift in 2020. As a result, they are both standing down from the workgroup.

@IanPartridge will work to hand over responsibilities for the Swift Docker images and suggested a potential new owner from the community.

The workgroup thanked @IanPartridge, @Chris_Bailey and the rest of the IBM team for their valuable work over the years in getting Swift on server off the ground, and providing the community with reliable solutions during those early days.

大致意思是说,根据 IBM 公司的开源优先级评估后,决定 IanPartridgeChris_Bailey 将于 2020 年不再继续从事 Swift 相关的工作了,同时他们也将退出 workgroup

其中,IanPartridge 将不再负责 Swift Docker images 相关的职责,社区将会有一名新的继承者来接管。

可以看出 IBM 在未来将会一定程度上减少 Swift 服务端的投入,算是 Swift 社区的一个损失。

目前主要由 Apple 官方维护的 Swift 库如下:

Event-driven network application framework for high performance protocol servers & clients, non-blocking.

A Logging API for Swift

A Metrics API for Swift

Metrics backend for swift-metrics that uses the statsd protocol.

目前 Swift 社区主要有如下 Web 框架:

另外,Swift 社区还有很多优秀的开源库,这里就不一一列出来了。

从目前来看,Vapor 框架的受关注度最高,且社区相对比较活跃。而且 Vapor 框架的作者 Logan Wright (@loganwright, Vapor) 和 Tanner Nelson (@tanner0101, Vapor) 均为 SSWG(Swift Server Work Group) 成员,与 Swift 官方组织联系也最为紧密,Vapor 几乎也都是第一时间采用 Swift 官方组件(比如:SwiftNIOSwiftLogSwiftMetrics 等)。

继续阅读“Swift 服务端发展现状”

Swift Weekly 中文 – Issue #175

本篇为译文,原文可见:链接

本周的 issue ,我们主要讨论 Thread SanitizerKeyValuePairsSPMUtility

文章

学习在 Swift 中如何使用 Thread Sanitizer to catch Data Races。修复怪异的 crash,并且可以看到 Data Reace 示例。

介绍了一些集合类型之间的区别,比如:ArraySetDictionary

本篇文章中,Derik Ramirez 将介绍如何使用 Swift Package Manager 中的 SPMUtility 模块,通过 ArgumentParser 来解析你的 swift command-line tool 的参数。

Xcode 11 介绍了一种新方式来测试可选类型。Sarun 向你演示了新的 XCTUnwrap 方法。

本周,John Sundell 看了看一些核心语言特性,这些特性可以使我们设计真正轻量级的 Swift API,并且可以帮助我们更好的开发一个新功能或系统。

如果你正在查找关于 body 是计算型时,去尝试修改 view 状态的资料的话,这篇文章将会告诉你可以做哪些操作以及不应该做哪些操作。

在本周文章中,Majid 将向你展示 UIKitSwiftUI 开发之间的主要不同点,并指出使用 SwiftUI 的时候必须要改变的习惯。

Alexey Naumov 解释了如何处理 SwiftUI 项目中的导航来实现 deep links

工作机会

Ctrl Group builds digital products for patients, healthcare practitioners and researchers to gather evidence and provide better care. We’re looking for an iOS engineer to join our team in London, or work remotely as part of our distributed team.

讨论

介绍了今年十月在 Bologna, Italy 举办的 #Pragma Conference 中的所有演讲 。

两个免费视频探索了 Apple 新的 Combine 框架,包括它的核心组件,以及如何集成进你的代码。

库 & 代码

继续阅读“Swift Weekly 中文 – Issue #175”

Vapor 4.0.0 Beta 3 发布

更新日志

Example output:

# TYPE http_requests_total counter
http_requests_total 0
http_requests_total{status="200", path="GET /hello/:name", method="GET"} 7
http_requests_total{status="200", path="GET /metrics", method="GET"} 3
# TYPE http_request_duration_seconds summary
http_request_duration_seconds{quantile="0.01"} 0.000115894
http_request_duration_seconds{quantile="0.05"} 0.000115894
...
  • Updates to RoutingKit beta 3 (#2126)

  • ClientResponse, HTTPStatus, and HTTPHeaders are now Codable (#2124)

  • Environment variables loaded from .env files can now be accessed immediately after Application has initialized (#2125)

.env (in same folder as Package.swift)

FOO=BAR

main.swift

let app = Application(...)
defer { app.shutdown() } 

let foo = Environment.get("FOO") 
print(foo) // BAR

iOS集成Flutter模块

本文主要介绍原生 iOS 应用如何集成 Flutter 模块。

安装 Flutter

Flutter 支持 macOSWindowsLinux

安装步骤可见官网:https://flutter.dev/docs/get-started/install

(注:本教程使用的是 macOS 系统)

iOS 集成 Flutter 模块

通过 Xcode 创建一个 iOS 原生项目,命名为 Example-Flutter

  1. 通过终端进入 Example-Flutter 当前目录下。
  2. 通过如下命令来创建 Flutter 模块。
flutter create --template module my_flutter

将会生成一个 my_flutter 新目录,结构如下:

my_flutter/
├─.ios/
│ ├─Runner.xcworkspace
│ └─Flutter/podhelper.rb
├─lib/
│ └─main.dart
├─test/
└─pubspec.yaml
  1. 通过 CocoaPods 集成 Flutter 模块。

Example-Flutter 项目目录下创建 Podfile 文件,内容编辑如下:

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '9.0'
use_frameworks!

flutter_application_path = './my_flutter'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')

target 'Example-Flutter' do
    install_all_flutter_pods(flutter_application_path)
end

然后,通过 pod install 命令集成 Flutter 模块到 iOS 工程项目中。

输出类似如下日志:

$ pod install
Analyzing dependencies
Downloading dependencies
Installing Flutter (1.0.0)
Installing FlutterPluginRegistrant (0.0.1)
Installing my_flutter (0.0.1)
Generating Pods project
Integrating client project

[!] Please close any current Xcode sessions and use `Example-Flutter.xcworkspace` for this project from now on.
Pod installation complete! There are 3 dependencies from the Podfile and 3 total pods installed.

此时,整个项目的目录结构类似是这样的。

some/path/Example-Flutter
├── Example-Flutter/
├── Example-Flutter.xcodeproj
├── Example-Flutter.xcworkspace
├── my_flutter/
│   └── .ios/
│       └── Flutter/
│         └── podhelper.rb
├── Podfile
├── Podfile.lock
└── Pods/
  1. 添加 Flutter 相关代码

修改 AppDelegate.swift 文件。

import FlutterPluginRegistrant
lazy var flutterEngine = FlutterEngine(name: "my flutter engine")

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.
    flutterEngine.run()
    GeneratedPluginRegistrant.register(with: self.flutterEngine);

    return true
}

然后在 iOS 原生页面上添加相应代码。

导入 Flutter package。

import Flutter

增加一个触发按钮,代码如下:

let button = UIButton(type:UIButton.ButtonType.custom)
button.addTarget(self, action: #selector(showFlutter), for: .touchUpInside)
button.setTitle("Show Flutter!", for: UIControl.State.normal)
button.frame = CGRect(x: 80.0, y: 210.0, width: 160.0, height: 40.0)
button.backgroundColor = UIColor.blue
self.view.addSubview(button)

响应 Button 点击事件,代码如下:

@objc func showFlutter() {
  let flutterEngine = (UIApplication.shared.delegate as! AppDelegate).flutterEngine
  let flutterViewController =
      FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)
  present(flutterViewController, animated: true, completion: nil)
}

运行效果

  • iOS 原生页面

  • 点击按钮后,显示 Flutter 页面效果。

示例代码

GitHub: iOS-Examples/Example-Flutter