Algorithm
本周选择的算法题是:Spiral Matrix II
规则如下:
Given a positive integer n, generate a square matrix filled with elements from 1 to n2 in spiral order.
Example:
Input: 3
Output:
[
[ 1, 2, 3 ],
[ 8, 9, 4 ],
[ 7, 6, 5 ]
]
Solution
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
ans = [[0] * n for i in range(n)]
def get_num(r1, c1, r2, c2):
for r in range(r1, r2 + 1):
yield c1, r
for c in range(c1 + 1, c2 + 1):
yield c, r2
for r in range(r2 - 1, r1, -1):
yield c2, r
for c in range(c2, c1, -1):
yield c, r1
r1, r2 = 0, n - 1
c1, c2 = 0, n - 1
i = 1
while r1 <= r2 and c1 <= c2:
for c, r in get_num(r1, c1, r2, c2):
ans[c][r] = i
i += 1
r1 += 1; r2 -=1; c1 += 1; c2 -= 1
return ans
Review
Why doesn’t set -e (or set -o errexit, or trap ERR) do what I expected?
这篇文章介绍了 bash 严格模式 set -e
的不可预测性。
我们一开始使用 set -e
的初衷是好的,希望找到一种高效的方式处理错误,尽可能将错误提前暴露,避免向下传递。set -e
在此场景下很有用,同时它的副作用也很明显,那就是不可预测性。
实际上并不是所有的错误都需要处理,比如:
flutter clean
会在没有.packages
时报错(第一次当然不会有了,这个错误忽略即可)rm file
文件不存在时grep a b
找不到对应的字符时- …
想用好 set -e
就要保证每一个潜在的错误都有对应的错误处理程序,如:
grep cat food || echo "$0: no cat in the food" >&2
trap 'do_something' ERR
一个不算复杂的 sh 文件都会有很多意想不到的错误 case 需要处理,所以 set -e
在开发者群体内并不流行,大多数时候还是靠手动处理更高效、可靠。
Tip
macOS 虚拟化改进
早前我们将 macOS 也打包成了虚拟化环境,然后通过「自动登录+launchd」实现自启动服务。
但是实践下来总体感觉不够稳定,主要原因是想通过 launchd
完全模拟一个登录用户很麻烦,比如我们的虚拟化环境主要是为 CI 服务,包含了打包、自动化测试等基本服务,需要用到 xcodebuild
等基础软件,通过 xcodebuild 调用模拟器时又需要 Aqua
的支持,于是 launchd
中还需要增加 LimitLoadToSessionType
的配置。环境变量也一样,如果 EnvironmentVariables
不包含合适的配置连最基本的像 python3
之类的软件也无法运行。
我们目前正在尝试的解决方案也很简单,把直接通过 launchd
启动的服务用 Terminal
来启动:
<key>ProgramArguments</key>
<array>
<string>open</string>
<string>-a</string>
<string>Terminal</string>
<string>/path/to/run_service.sh</string>
</array>
确保是一次完整的登录用户调用以及 GUI 是可用的。
Share
CocoaPods 两周前发布了 1.10 的正式版本,相比我们目前使用的 1.8.4 有许多更新:
- 增加了对 Xcode 12 完整的支持
- 增加了对 XCFramework 的支持(1.8.4 对此会编译报错)
- 支持在 Test Specs 里配置代码覆盖率(我们目前的单元测试方案)
- 支持配置
use_frameworks!
是以静态还是动态库的方式链接 - 从 Ruby 2.0 升级到了 2.7(macOS 很多年前就去掉了对 2.0 的支持)
在 CocoaPods 1.10 文末 What’s Next 里有这么一段话:
Additionally, we are still considering adding support for local sources that would be helpful for monorepos and allow CocoaPods to discover local pods automatically.
from: https://blog.cocoapods.org/CocoaPods-1.10.0-beta/
在开源社区里有很多采用了 monorepo 的代码结构管理方式,比如像 React 这类前端库,他们往往会以「组件库」为单位一起发布,避免每个组件都有自己的独立版本号,修复 Bugs 时也能在同一条 commit 里看到多个组件的修改记录(原子性的提交),维护起来方便许多,同时也适合做大规模的重构,尤其是对小团队而言。
monorepo 虽然在物理上没有将组件之间隔离开,但是每个组件还是应该保持独立迭代的特点,尽量减少组件之间的耦合。
我们从去年开始实践 monorepo,由于 CocoaPods 原生不支持,我们为此开发了相关的插件,希望早日看到官方的实现,如此便能帮助更多团队落地 monorepo。