[TIL] 年复一年意识到成长的四月

记录日常开发中遇到的 1. 新知 2. 对旧知识的新认知 3. 重新唤起的记忆 4. review 中遇到的一些有趣的问题

04/23


UTI - Uniform Type Identifier

同事在分享会中详细讲了 UTI,用过很多次,但大概一直都只懂三成吧,听完后对 UTI 的理解明显更系统化了一些XD

能一瞬间想起来的运用场景有:

  1. Share Extension
  2. Drag and Drop
  3. Pasteboard

简单来说,对于文本类型而言,扩展名可以是 .txt.text,而 MIME 类型是 text/plain,当我们要处理文本类型时,必须将以上所有类型全部视为对象,这是一件非常缺乏效率的事情,而 UTI 就是用来处理这个问题的,他将所有类型都统一为了 public.text,UTI 类型和其他所有类型相互兼容。

Ref:关于自定义 UTI 类型,UTI 类型的继承性 — https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/understandingutis/understandutisconc/understandutis_conc.html

04/20


autoreleasepool

最近做了一点 Objective-C 转 Swift,在 Objective-C 中我们常常会需要使用 autoreleasepool,但并不意味着遇到 Swift 之后 autoreleasepool 就不再需要考虑。当 Swift 调用 Objective-C 代码,亦或是 Objective-C 调用被标记为 @objc 的 Swift 方法时,如果方法返回的是 autorelease 的值,那 Swift 也会保持这个值的 autorelease 特性。

在 Objective-C 中,有时候会在循环中写 autoreleasepool 来避免内存爆炸,因为循环的持续会导致没有机会自动释放内存。

04/15


ZIPFoundation

https://thomas.zoechling.me/journal/2017/07/ZIPFoundation.html

A ZIP compression framework don't based on any 3rd party framework. Almost all of the swift ZIP framework based on minizip.

尽管这个框架十分简洁甚至无法完全满足要求,但作者的这篇文章还是很值得一读,在设计框架时考虑的一些点很有参考价值。

ZIP64

https://en.wikipedia.org/wiki/ZIP(fileformat)#ZIP64

标准 ZIP 有一些限制,例如不能容纳超过 65535 个文件(因为 eocd 中只有 2 bytes 用来存 entry 的信息。。),压缩文件大小不能超过 4G 之类,因此出现了 ZIP64 标准。

04/13


CRC32 (Cyclic redundancy check)

ZIP 压缩中使用的校验方式是 CRC32,是 CRC(循环冗余校验)方法中的其中一种。

记忆中第一次知道 CRC 是在密码学的课本上,奇偶校验,50% 的出错概率,还有校验和,也有不小的出错可能性,此外就是 CRC 了,因为高效且检错力很高,被广泛用在存储,压缩等之中。CRC32 是 CRC 校验中最被广泛使用的之一,但他并不是完美的,即便篡改了内容,用 CRC32 进行校验依然可能会得到相同的值。

题外话,如何在各种语言中使用 CRC32:https://rosettacode.org/wiki/CRC-32#Swift。Swift 的实现法可以说并不一定实用,他选择了直接调用 zlib 中的 crc32 方法w

Strange Date Format

e.g. 04/01, template = "Md"

en_US ⇒ 4/1

ja_JP ⇒ 4/1

en_JP ⇒ 04/01

https://stackoverflow.com/questions/67073224/get-a-unexpected-date-string-when-setting-template-to-md

Still don‘t know why Apple making this design..But we could resolve this unexpected problem by:

formatter.dateFormat = DateFormatter.dateFormat(
    fromTemplate: " Md",
    options: 0,
    locale: Locale(identifier: "en_JP")
)?
.replacingOccurrences(of: "MM", with: "M")
.replacingOccurrences(of: "dd", with: "d")

04/12


SQL - Prepared Statement

INSERT INTO products (name, price) VALUES (?, ?);

通常这么做的优点是:

  1. 防止 SQL 注入
  2. 效率更高,避免了多次解析相同结构的 SQL 语句
  3. ...

04/08


Attributes in Swift

分为两类,分别是:

1. @attribute name
2. @attribute(attribute arguments)

今天写了写 @inline,回忆了几个常用的:

@inline 内联

在编译的阶段用函数体去替换函数调用。优点是可以减少函数调用的开销,但作为交换,binary size 会略有增大。

  • @inline(_always) 强制内联(不是 100%,也有例外)
  • @inline(never) 无论如何都不内联

@inlinable 可内联

和 @inline 看起来很像,但有着本质上的区别。@inlinable 可以用在 public 和 internal 的方法,计算属性等之上,这样在模块外被进行编译的时候,就会进行内联优化。虽然可以被优化,但 internal 依然是不可以被访问的,另外,当且仅但 internal 被标记为 @usableFromInline 的时候才会被作为对象。如果只存在一个模块,并没有只用 @inlinable 的必要。

@discardableResult 可忽略的返回值

允许有返回值的方法不返回任何值

@available

是一个带有参数的 attribute,用于指定最低 swift 版本,platform 的版本之类,例如我们会写 @available(swift 99) 来避免被 swift 调用,@available(iOS 14.0) 来使用 14.0 最新的 API。

Ref. https://docs.swift.org/swift-book/ReferenceManual/Attributes.html#

04/07


Access Photo Library

Plist

  • NSPhotoLibraryAddUsageDescription
  • NSPhotoLibraryUsageDescription
  • NSCameraUsageDescription

Render a UIView to a UIImage

let renderer = UIGraphicsImageRenderer(size: view.bounds.size)
let image = renderer.image { context in
    view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
}

Take screenshot programmatically

https://developer.apple.com/library/archive/qa/qa1703/_index.html (Outdated..)

04/06


Multi-cursor editing in Xcode

  • To add a new cursor, hold Control and SHIFT then click.
  • Hold Control and SHIFT then ↑ or ↓
  • Hold Option then drag cursor around.

Formatter

https://nshipster.com/formatter/

当不设置默认 template 的情况下,会按照各 locale 的默认模版来显示日期。

例如:

// JP: 2021/03/01
// KR: 2021.3.1.

let formatter = DateFormatter()
formatter.locale = locale
formatter.calendar = Calendar.autoupdatingCurrent
formatter.dateStyle = .short
formatter.timeStyle = .none

这应当被认为是一个好的实践,完全可以当且仅当必要的时候为 formatter 设置 template。

Detect user takes a screenshot

NotificationCenter.default.addObserver(
    self,
    selector: #selector(xxxxxx),
    name: UIApplication.userDidTakeScreenshotNotification,
    object: nil
)

根据文档可以知道,这个通知的 userInfo 中并不包含任何信息,一个有些令人绝望的消息。考虑两个方案来获得图片。

  1. 从相册读取第一张照片,多少有些 workaround 的意味,并且需要相册权限。
  2. 重新截取图片,潜在的问题是截图和系统截图可能存在差异。

04/05


Long polling

长轮询,与轮询的区别在于,后者是 client 定期去拉取更新,经常会得到空 response;而长轮询会 hold 住连接,直到 server 有更新才会返回。看似一种 push 的方式,本质上还是 pull。

04/02


XCTUnwrap()

https://www.hackingwithswift.com/example-code/testing/how-to-check-and-unwrap-optionals-in-tests-using-xctunwrap

Easy to read than guard and let..