摸鱼精选第 31 期

1. How to Create a Custom Debounce Hook with React

学习怎么使用 useEffect 定制一个自己的 hook。

import { useEffect, useRef, useState } from 'react';

const useDebounce = (value, delay = 500) => {
  const [debouncedValue, setDebouncedValue] = useState('');
  const timerRef = useRef();

  useEffect(() => {
    timerRef.current = setTimeout(() => setDebouncedValue(value), delay);

    return () => {
      clearTimeout(timerRef.current);
    };
  }, [value, delay]);

  return debouncedValue;
};

2. 《现代 JavaScript 高级教程》

可能是市面上比较好的 Javascript 高级教程,适合有一定 Javascript 基础的同学学习。

作者很高产,写了很多其他的教程:

3. TCP 长连接 CWND reset 的问题分析

这篇文章是关于 TCP 长连接 CWND reset 的问题分析。作者在文章中描述了一个用户工单,其中用户在一个 50ms 延迟的环境中调用其他服务的延迟远大于 50ms,有 200ms 左右的延迟。作者通过分析日志和询问开发团队,最终发现问题是由一个 TCP 行为导致的。

4. SwiftUI Index

SwiftUI 的 View 和 Environment 变量索引, 支持 iOS 13 到 17 的版本。

5. UICollectionView Tutorial: Headers, Selection and Reordering

UICollectionView 的一些新接口用法,尤其是 Drag and Drop 接口。这个新接口是 iOS 11.0 就已经支持的了,但是我们日常开发中比较少用到。

6. A few Xcode debugging tips

一些 Xcode 调试小技巧:

  • Symbolic Breakpoint:

可以在 Symbol 输入实例方法- [UIViewController viewDidLoad],这样每次调用这个方法的时候就会自动断点。然后,还可以在 Action 增加 Log Message,输入%B,选择 Log message to console ,或者增加Debugger Command, 输入 po $arg1表示 lldb 打印实例方法的参数 1。最后可以勾选Automatically continue after evaluating actions,表示执行 action 之后继续运行,不中断。

  • expr

这是 lldb 的其中一个命令,在Debugger Command添加 expr <expression>,其中 可以是任何合法的 C、C++、Objective-C 或 Swift 表达式。expr 命令会在当前上下文中计算这个表达式,并将结果打印到终端上,也可以使用这个表达式来改变变量值。

bash expr emailTextField.text = "some@google.com" expr add(x, y)

  • thread return

    这个命令也是在Debugger Command,可以改变返回结果

    bash thread return .TimeInterval(interval: 86400)

7. Push Notifications Console

Apple 官方的 APNs 调试控制台 web 网站,可以自定义各种消息,应该会比第三方的推送服务更稳定吧。

8. Fastlane 提出的 Code Signing 集中管理方法

iOS 团队中大于 2 个人就遇到这种自动签名的问题,每个人都创建一个自己的 Development 和 App Store Distribution 的证书。但是 Profile 只认一个 Distribution 证书,每个人的创建日期又不一样,导致证书经常过期或者不知道使用睡的证书。

Fastlane 提出的一个办法就是将证书 key 保存在一个 git 仓库中,集中式管理,避免每个人手动创建的混乱。

9. MMBAlertsPickers

这个开源库有意思的点是使用UIAlertController的私有属性contentViewController自定义一个 Alert 效果。

还可以看下iOS UIAlertController 高级自定义,这篇文章列举了 UIAlertController 所有的私有 api。

10. iOS 混编|为 Swift 重命名 Objective-C API

Swift 和 Objective-C 的 API 命名规范有些不同,在混编时,虽然编译器会根据一些规则重命名 Objective-C 与 Swift API 且通常结果还不错,但这毕竟是计算机的审美结果,有时会不尽如人意。本篇文章讲解了如何自定义重命名 Objective-C 与 Swift API,掌握它们就可以人为地改进重命名的 API,提升混编体验。

Apple 给的示例中 `NS_SWIFT_NAME`` 的应用场景:

  • 重命名与 Swift 风格不符的 API,使其在 Swift 中有合适的名称;
  • 将与类 A 相关联的类/枚举作为内部类/枚举附属于类 A;
  • 重命名 “命名去掉完整前缀后以数字开头的” 枚举的 case,改善所有 case 导入到 Swift 中的命名;
  • 重命名 “命名不满足自动转换为构造器导入到 Swift 中的约定的” 工厂方法,使其作为构造器导入到 Swift 中(不能用于协议中);
  • 在处理全局常量、变量,特别是在处理全局函数时,它的能力更加强大,能够极大程度地改变 API。比如可以将 全局函数 转变为 静态方法,或是 实例⽅法,甚至是 实例属性。如果你在 Objective-C 和 Swift 里都用过 Core Graphics 的话,你会深有体会。Apple 称其把 NS_SWIFT_NAME 用在了数百个全局函数上,将它们转换为方法、属性和构造器,以更加方便地在 Swift 中使用。

11. iOS 17: Notable UIKit Additions

iOS 17 中 UIKit 更新内容,作者很厉害,连续多年 WWDC 之后都写了类似的文章,包括 iOS 11, iOS 12, iOS 13, iOS 14, iOS 15, iOS 16

12. 避免 SwiftUI 视图的重复计算

可以驱动视图进行更新的源被称之为 Source of Truth,它的类型有:

  • 使用 @State、@StateObject 这类属性包装器声明的变量
  • 视图类型( 符合 View 协议 )的构造参数
  • 例如 onReceive 这类的事件源

避免重复计算的方法也就是针对这几个数据源的改变,尽量避免全局状态,尤其是 @EnvironmentObject 环境变量,只要声明了这个变量,无论使用与否都会在变量改变之后刷新。

其他建议

  • 需要跳跃视图层级时,考虑使用 Environment 或 EnvironmentObject
  • 对于不紧密的 State 关系,考虑在同一个视图层级使用多个 EnvironmentObject 注入,将状态分离
  • 在合适的场景中,可以使用 objectWillChange.send 替换 @Published
  • 可以考虑使用第三方库,对状态进行切分,减少视图刷新几率
  • 无需追求完全避免重复计算,应在依赖注入便利性、应用性能表现、测试难易度等方面取得平衡
  • 不存在完美的解决方案,即使像 TCA 这类的热门项目,面对切分粒度高、层次多的 State 时,也会有明显的性能瓶颈

13. From SVG to Canvas – Part 2: A new way of building interactions

这篇文章主要讲了作者的团队为什么要将 SVG 转换为 Canvas。作者的团队在使用 React 处理与 SVG 交互时遇到了一些问题,他们希望能够找到更好的方法来编写交互处理代码。因此,他们决定从头开始编写一个新的交互处理系统,并使用 Canvas 来实现他们的目标。

14. Etcd/Raft 原理篇

  • etcd/raft 实现为一个单独包,以 sdk 的方式接入到 etcd 系统中,外部使用者同样也可以单独使用改 sdk;具体如何使用以及其工程实现将会在第二篇分享。
  • 实现架构上有最小原则设计可以在后续开发中借用参考。
  • 重点介绍了日志复制功能,包括其存储结构、流转方式以及 Leader 管理其他节点日志复制进度的实现方式。
  • 日志复制过程中通过Inflights 算法实现流量控制,实现非常巧妙。
  • 选举功能实现上也比较巧妙,函数指针的方式通过一个 Step 函数解决不同角色的自定义功能。
  • 集群中节点状态变更、配置变更等都是共用的通过日志复制的传输链路,保证代码实现简洁抽象。

15. How to use scroll view in Interface Builder / Storyboard (Xcode 11)

2019 年的老文,但是这个知识点很多人不会用。其实就是 UIScrollViewContent Layout GuideFrame Layout Guide

16. 从零开始写 OS

本系列文章记录了使用 Rust 编程语言编写一个小型操作系统的详细过程。每篇文章包含所需所有所需代码和相关知识点讲解。

17. Working with native elements in Flutter: Platform Channel vs Pigeon vs Foreign Function Interface (FFI)

目前 flutter 和原生之间的互相调用方法有三种:Platform Channel ,官方库 Pigeon,FFI。

18. 【关于 NLP】 那些你不知道的事

该仓库主要记录 NLP 算法工程师相关的顶会论文研读笔记。

19. Effective Debugging

讲述了如何更有效率地调试大型程序(以 C/C++为例)的方法和技能。书中例子不仅丰富而且都是从实际的工作经验提取,观点和方法有效且具有可行性。

涉及的话题有:

  • 调试符号
  • 内存管理器数据结构
  • 如何调试内存损坏 bug
  • C/C++对象布局
  • 如何拓展调试器
  • 优化后的程序怎么调试
  • 进程镜像
  • 等等

20. C++17’s Useful Features for Embedded Systems

可用于嵌入式系统的 C++ 17 功能,应该不多吧,嵌入式能兼容到 C++ 14 就不错了。

21. Introduction to Compilers and Language Design

这是一本免费的在线教科书。

编译器将用高级语言编写的程序翻译成用较低级语言编写的程序。对于计算机科学专业的学生来说,从头开始构建编译器是一个必经之路:一个具有挑战性且有趣的项目,它提供了对计算机科学许多不同方面的深入了解,其中一些方面理论性很强,另一些方面则非常实用。

本书提供了一个学期的编译器构建介绍,使读者能够构建一个简单的编译器,该编译器接受类似 C 的语言并将其转换为工作的 X86 或 ARM 汇编语言。它最适合具有一定 C 语言编程经验并学过数据结构和计算机体系结构课程的本科生。