uikit-expert

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

UIKit Expert Skill

UIKit专家技能

Overview

概述

Use this skill to build, review, or improve UIKit features with correct lifecycle management, performant Auto Layout, modern collection view APIs, and safe navigation patterns. Prioritize native APIs, Apple's documented best practices, and performance-conscious patterns. This skill focuses on facts and best practices without enforcing specific architectural patterns (no MVVM/VIPER/Coordinator mandates).
使用本技能构建、评审或优化UIKit功能,确保正确的生命周期管理、高性能的Auto Layout、现代集合视图API以及安全的导航模式。优先使用原生API、苹果官方文档推荐的最佳实践和注重性能的设计模式。本技能聚焦于事实与最佳实践,不强制特定架构模式(无MVVM/VIPER/Coordinator等要求)。

Workflow Decision Tree

工作流决策树

1) Review existing UIKit code

1) 评审现有UIKit代码

  • Check view controller lifecycle usage —
    viewIsAppearing
    for geometry,
    viewDidLoad
    for setup only (see
    references/view-controller-lifecycle.md
    )
  • Verify Auto Layout correctness — batch activation, no constraint churn,
    translatesAutoresizingMaskIntoConstraints
    (see
    references/auto-layout.md
    )
  • Check collection/table view APIs — diffable data sources, stable identity, CellRegistration (see
    references/modern-collection-views.md
    )
  • Verify cell configuration uses
    UIContentConfiguration
    , not deprecated
    textLabel
    (see
    references/cell-configuration.md
    )
  • Check list scroll performance — prefetching, cell reuse cleanup, reconfigureItems (see
    references/list-performance.md
    )
  • Verify navigation patterns — bar appearance all 4 slots, no concurrent transition crashes (see
    references/navigation-patterns.md
    )
  • Check animation correctness — API selection, PropertyAnimator state machine, constraint animation (see
    references/animation-patterns.md
    )
  • Audit memory management —
    [weak self]
    , delegate ownership, Timer/CADisplayLink traps (see
    references/memory-management.md
    )
  • Check concurrency safety — Task lifecycle, cancellation in viewDidDisappear (see
    references/concurrency-main-thread.md
    )
  • If SwiftUI interop present — verify UIHostingController containment, sizingOptions (see
    references/uikit-swiftui-interop.md
    )
  • Check image loading — downsampling, cell reuse race condition (cancel/clear/verify) (see
    references/image-loading.md
    )
  • Verify keyboard handling — UIKeyboardLayoutGuide over manual notifications (see
    references/keyboard-scroll.md
    )
  • Check trait handling and accessibility — registerForTraitChanges, Dynamic Type, VoiceOver (see
    references/adaptive-appearance.md
    )
  • Validate modern API adoption and iOS 26+ availability handling (see
    references/modern-uikit-apis.md
    )
  • 检查视图控制器生命周期的使用:几何相关操作使用
    viewIsAppearing
    ,仅在
    viewDidLoad
    中执行初始化设置(详见
    references/view-controller-lifecycle.md
  • 验证Auto Layout的正确性:批量激活约束、避免约束频繁重建、正确设置
    translatesAutoresizingMaskIntoConstraints
    (详见
    references/auto-layout.md
  • 检查集合/表格视图API:使用差分数据源、稳定标识符、CellRegistration(详见
    references/modern-collection-views.md
  • 验证单元格配置使用
    UIContentConfiguration
    ,而非已废弃的
    textLabel
    (详见
    references/cell-configuration.md
  • 检查列表滚动性能:预加载、单元格复用清理、使用
    reconfigureItems
    (详见
    references/list-performance.md
  • 验证导航模式:配置全部4个导航栏外观插槽、避免并发转场崩溃(详见
    references/navigation-patterns.md
  • 检查动画正确性:API选择、PropertyAnimator状态机、约束动画(详见
    references/animation-patterns.md
  • 审计内存管理:使用
    [weak self]
    、委托所有权、Timer/CADisplayLink陷阱规避(详见
    references/memory-management.md
  • 检查并发安全性:Task生命周期管理、在
    viewDidDisappear
    中取消任务(详见
    references/concurrency-main-thread.md
  • 若存在SwiftUI互操作:验证UIHostingController的容器化、sizingOptions设置(详见
    references/uikit-swiftui-interop.md
  • 检查图片加载:降采样处理、单元格复用竞争条件(取消/清空/验证)(详见
    references/image-loading.md
  • 验证键盘处理:使用UIKeyboardLayoutGuide替代手动通知监听(详见
    references/keyboard-scroll.md
  • 检查特性处理与无障碍支持:注册
    traitChanges
    、动态字体、VoiceOver(详见
    references/adaptive-appearance.md
  • 验证现代API的采用以及iOS 26+兼容性处理(详见
    references/modern-uikit-apis.md

2) Improve existing UIKit code

2) 优化现有UIKit代码

  • Replace geometry work in
    viewDidLoad
    with
    viewIsAppearing
    (see
    references/view-controller-lifecycle.md
    )
  • Eliminate constraint churn — create once, toggle
    isActive
    or modify
    .constant
    (see
    references/auto-layout.md
    )
  • Migrate from legacy
    UITableViewDataSource
    to diffable data sources (see
    references/modern-collection-views.md
    )
  • Replace deprecated
    textLabel
    /
    detailTextLabel
    /
    imageView
    with
    UIContentConfiguration
    (see
    references/cell-configuration.md
    )
  • Replace
    reloadItems
    with
    reconfigureItems
    for in-place cell updates (see
    references/list-performance.md
    )
  • Fix navigation bar appearance — set all 4 appearance slots, use
    navigationItem
    not
    navigationBar
    (see
    references/navigation-patterns.md
    )
  • Improve animations — use PropertyAnimator for gestures, correct constraint animation pattern (see
    references/animation-patterns.md
    )
  • Fix retain cycles — add
    [weak self]
    , cancel Tasks in
    viewDidDisappear
    , use block-based Timer (see
    references/memory-management.md
    )
  • Migrate GCD to Swift concurrency — replace
    DispatchQueue.main.async
    with
    Task
    (see
    references/concurrency-main-thread.md
    )
  • Suggest image downsampling when
    UIImage(data:)
    or full-resolution loading detected (as optional optimization, see
    references/image-loading.md
    )
  • Replace keyboard notification handling with
    UIKeyboardLayoutGuide
    (see
    references/keyboard-scroll.md
    )
  • Replace
    traitCollectionDidChange
    with
    registerForTraitChanges
    (see
    references/adaptive-appearance.md
    )
  • Adopt iOS 26 APIs where appropriate — Observation, updateProperties(), .flushUpdates (see
    references/modern-uikit-apis.md
    )
  • viewDidLoad
    中的几何相关操作迁移至
    viewIsAppearing
    (详见
    references/view-controller-lifecycle.md
  • 消除约束频繁重建:一次性创建约束,通过切换
    isActive
    或修改
    .constant
    来调整(详见
    references/auto-layout.md
  • 从旧版
    UITableViewDataSource
    迁移至差分数据源(详见
    references/modern-collection-views.md
  • UIContentConfiguration
    替代已废弃的
    textLabel
    /
    detailTextLabel
    /
    imageView
    (详见
    references/cell-configuration.md
  • reconfigureItems
    替代
    reloadItems
    实现单元格原地更新(详见
    references/list-performance.md
  • 修复导航栏外观问题:配置全部4个外观插槽,使用
    navigationItem
    而非
    navigationBar
    (详见
    references/navigation-patterns.md
  • 优化动画:为手势使用PropertyAnimator、采用正确的约束动画模式(详见
    references/animation-patterns.md
  • 修复循环引用:添加
    [weak self]
    、在
    viewDidDisappear
    中取消Tasks、使用基于block的Timer(详见
    references/memory-management.md
  • 将GCD迁移至Swift并发:用
    Task
    替代
    DispatchQueue.main.async
    (详见
    references/concurrency-main-thread.md
  • 当检测到使用
    UIImage(data:)
    或全分辨率加载时,建议对图片进行降采样(可选优化,详见
    references/image-loading.md
  • UIKeyboardLayoutGuide
    替代键盘通知监听(详见
    references/keyboard-scroll.md
  • registerForTraitChanges
    替代
    traitCollectionDidChange
    (详见
    references/adaptive-appearance.md
  • 酌情采用iOS 26 API:Observation、updateProperties()、.flushUpdates(详见
    references/modern-uikit-apis.md

3) Implement new UIKit feature

3) 实现新UIKit功能

  • Design data flow first: identify owned state, injected dependencies, and model layer
  • Set up view controller lifecycle correctly — one-time setup in
    viewDidLoad
    , geometry in
    viewIsAppearing
    (see
    references/view-controller-lifecycle.md
    )
  • Build Auto Layout with batch activation and zero churn (see
    references/auto-layout.md
    )
  • Use modern collection view stack: DiffableDataSource + CompositionalLayout + CellRegistration (see
    references/modern-collection-views.md
    )
  • Configure cells with
    UIContentConfiguration
    and
    configurationUpdateHandler
    (see
    references/cell-configuration.md
    )
  • Implement prefetching and proper cell reuse cleanup for lists (see
    references/list-performance.md
    )
  • Set up navigation with all 4 appearance slots and concurrent-transition guards (see
    references/navigation-patterns.md
    )
  • Choose correct animation API for the use case (see
    references/animation-patterns.md
    )
  • Use
    [weak self]
    in escaping closures, cancel Tasks in lifecycle methods (see
    references/memory-management.md
    )
  • Use
    @MainActor
    correctly, store Task references (see
    references/concurrency-main-thread.md
    )
  • If embedding SwiftUI — use full child VC containment for UIHostingController (see
    references/uikit-swiftui-interop.md
    )
  • Downsample images for display, handle cell reuse race condition (see
    references/image-loading.md
    )
  • Use
    UIKeyboardLayoutGuide
    for keyboard handling (see
    references/keyboard-scroll.md
    )
  • Support Dynamic Type, VoiceOver, dark mode from the start (see
    references/adaptive-appearance.md
    )
  • Gate iOS 26+ features with
    #available
    and provide sensible fallbacks (see
    references/modern-uikit-apis.md
    )
  • 先设计数据流:确定自有状态、注入依赖和模型层
  • 正确设置视图控制器生命周期:在
    viewDidLoad
    中执行一次性初始化,几何相关操作在
    viewIsAppearing
    中完成(详见
    references/view-controller-lifecycle.md
  • 构建Auto Layout时使用批量激活,避免约束频繁重建(详见
    references/auto-layout.md
  • 使用现代集合视图栈:DiffableDataSource + CompositionalLayout + CellRegistration(详见
    references/modern-collection-views.md
  • UIContentConfiguration
    configurationUpdateHandler
    配置单元格(详见
    references/cell-configuration.md
  • 为列表实现预加载和正确的单元格复用清理逻辑(详见
    references/list-performance.md
  • 配置导航时设置全部4个外观插槽,并添加并发转场防护(详见
    references/navigation-patterns.md
  • 根据使用场景选择正确的动画API(详见
    references/animation-patterns.md
  • 在逃逸闭包中使用
    [weak self]
    ,在生命周期方法中取消Tasks(详见
    references/memory-management.md
  • 正确使用
    @MainActor
    ,存储Task引用(详见
    references/concurrency-main-thread.md
  • 若嵌入SwiftUI:对UIHostingController使用完整的子VC容器化(详见
    references/uikit-swiftui-interop.md
  • 对显示用图片进行降采样,处理单元格复用竞争条件(详见
    references/image-loading.md
  • 使用
    UIKeyboardLayoutGuide
    处理键盘交互(详见
    references/keyboard-scroll.md
  • 从设计初期就支持动态字体、VoiceOver、深色模式(详见
    references/adaptive-appearance.md
  • #available
    对iOS 26+特性做版本隔离,并提供合理的降级方案(详见
    references/modern-uikit-apis.md

Core Guidelines

核心准则

View Controller Lifecycle

视图控制器生命周期

  • Use
    viewDidLoad
    for one-time setup: subviews, constraints, delegates — NOT geometry
  • Use
    viewIsAppearing
    (back-deployed iOS 13+) for geometry-dependent work, trait-based layout, scroll-to-item
  • viewDidLayoutSubviews
    fires multiple times — use only for lightweight layer frame adjustments
  • viewWillAppear
    is limited to transition coordinator animations and balanced notification registration
  • Always call
    super
    in every lifecycle override
  • Child VC containment:
    addChild
    addSubview
    didMove(toParent:)
    — in that exact order
  • Verify deallocation with
    deinit
    logging during development
  • viewDidLoad
    仅用于一次性初始化:添加子视图、设置约束、委托配置 — 不处理几何相关操作
  • viewIsAppearing
    (iOS 13+向后兼容)用于几何依赖操作、基于特性的布局、滚动到指定项
  • viewDidLayoutSubviews
    会触发多次 — 仅用于轻量级的图层帧调整
  • viewWillAppear
    仅用于转场协调器动画和对称的通知注册
  • 所有生命周期重写方法中必须调用
    super
  • 子VC容器化步骤:
    addChild
    addSubview
    didMove(toParent:)
    — 严格遵循此顺序
  • 开发阶段通过
    deinit
    日志验证对象是否被正确释放

Auto Layout

Auto Layout

  • Always set
    translatesAutoresizingMaskIntoConstraints = false
    on programmatic views
  • Use
    NSLayoutConstraint.activate([])
    — never individual
    .isActive = true
  • Create constraints once, toggle
    isActive
    or modify
    .constant
    — never remove and recreate
  • Never change priority from/to
    .required
    (1000) at runtime — use 999
  • Animate constraints: update constant → call
    layoutIfNeeded()
    inside animation block on superview
  • iOS 26+: use
    .flushUpdates
    option to simplify constraint animation
  • Avoid deeply nested UIStackViews in reusable cells
  • 所有通过代码创建的视图必须设置
    translatesAutoresizingMaskIntoConstraints = false
  • 使用
    NSLayoutConstraint.activate([])
    — 绝不单独设置
    .isActive = true
  • 一次性创建约束,通过切换
    isActive
    或修改
    .constant
    调整布局 — 绝不删除后重建
  • 运行时绝不改变优先级至/从
    .required
    (1000) — 使用999替代
  • 约束动画:更新constant值 → 在动画块中调用父视图的
    layoutIfNeeded()
  • iOS 26+:使用
    .flushUpdates
    选项简化约束动画
  • 可复用单元格中避免深度嵌套的UIStackView

Collection Views & Data Sources

集合视图与数据源

  • Use
    UICollectionViewDiffableDataSource
    with stable identifiers (UUID/database ID, not full model structs)
  • Use
    reconfigureItems
    for content updates,
    reloadItems
    only when cell type changes
  • Use
    applySnapshotUsingReloadData
    for initial population (bypasses diffing)
  • Use
    UICollectionViewCompositionalLayout
    for any non-trivial layout
  • Use
    UICollectionView.CellRegistration
    — no string identifiers, no manual casting
  • Use
    UIContentConfiguration
    for cell content and
    UIBackgroundConfiguration
    for cell backgrounds
  • Use
    configurationUpdateHandler
    for state-driven styling (selection, highlight)
  • 使用
    UICollectionViewDiffableDataSource
    并搭配稳定标识符(UUID/数据库ID,而非完整模型结构体)
  • 内容更新使用
    reconfigureItems
    ,仅在单元格类型改变时使用
    reloadItems
  • 初始数据填充使用
    applySnapshotUsingReloadData
    (跳过差分计算)
  • 任何非简单布局都使用
    UICollectionViewCompositionalLayout
  • 使用
    UICollectionView.CellRegistration
    — 无需字符串标识符,无需手动类型转换
  • 使用
    UIContentConfiguration
    配置单元格内容,
    UIBackgroundConfiguration
    配置单元格背景
  • 使用
    configurationUpdateHandler
    处理状态驱动的样式(选中、高亮)

Navigation

导航

  • Configure all 4
    UINavigationBarAppearance
    slots (standard, scrollEdge, compact, compactScrollEdge)
  • Set appearance on
    navigationItem
    (per-VC) in
    viewDidLoad
    , not on
    navigationBar
    in
    viewWillAppear
  • Use
    setViewControllers(_:animated:)
    for deep links — not sequential push calls
  • Guard against concurrent transitions — check
    transitionCoordinator
    before push/pop
  • Set
    prefersLargeTitles
    once on the bar; use
    largeTitleDisplayMode
    per VC
  • 配置全部4个
    UINavigationBarAppearance
    插槽(standard、scrollEdge、compact、compactScrollEdge)
  • viewDidLoad
    中为
    navigationItem
    (每个VC独立)设置外观,而非在
    viewWillAppear
    中设置
    navigationBar
  • 深度链接使用
    setViewControllers(_:animated:)
    — 不使用连续的push调用
  • 防护并发转场 — 执行push/pop前检查
    transitionCoordinator
  • 在导航栏上一次性设置
    prefersLargeTitles
    ;每个VC单独设置
    largeTitleDisplayMode

Animation

动画

  • UIView.animate
    — simple one-shot animations; check
    finished
    in completion
  • UIViewPropertyAnimator
    — gesture-driven, interruptible; respect state machine (inactive → active → stopped)
  • CABasicAnimation
    — layer-only properties (cornerRadius, shadow, 3D transforms); set model value first
  • iOS 17+ spring API:
    UIView.animate(springDuration:bounce:)
    aligns with SwiftUI
  • Constraint animation: flush layout → update constant → animate
    layoutIfNeeded()
    on superview
  • UIView.animate
    — 简单的一次性动画;在完成回调中检查
    finished
    状态
  • UIViewPropertyAnimator
    — 手势驱动、可中断的动画;遵循状态机(inactive → active → stopped)
  • CABasicAnimation
    — 仅图层属性(cornerRadius、阴影、3D变换);先设置模型值再添加动画
  • iOS 17+弹簧API:
    UIView.animate(springDuration:bounce:)
    与SwiftUI对齐
  • 约束动画:刷新布局 → 更新constant → 在动画块中调用
    layoutIfNeeded()

Memory Management

内存管理

  • Default to
    [weak self]
    in all escaping closures
  • Timer: use block-based API with
    [weak self]
    , invalidate in
    viewWillDisappear
  • CADisplayLink: use weak proxy pattern (no block-based API available)
  • NotificationCenter:
    [weak self]
    in closure, remove observer in
    deinit
  • Nested closures: re-capture
    [weak self]
    in stored inner closures
  • Delegates: always
    weak var delegate: SomeDelegate?
    with
    AnyObject
    constraint
  • Verify deallocation with
    deinit
    — if never called, a retain cycle exists
  • 所有逃逸闭包默认使用
    [weak self]
  • Timer:使用基于block的API并搭配
    [weak self]
    ,在
    viewWillDisappear
    中失效
  • CADisplayLink:使用弱代理模式(无基于block的API)
  • NotificationCenter:闭包中使用
    [weak self]
    ,在
    deinit
    中移除观察者
  • 嵌套闭包:在存储的内部闭包中重新捕获
    [weak self]
  • 委托:始终声明为
    weak var delegate: SomeDelegate?
    并添加
    AnyObject
    约束
  • 通过
    deinit
    验证对象释放 — 若未调用则存在循环引用

Concurrency

并发

  • UIViewController
    is
    @MainActor
    — all subclass methods are implicitly main-actor
  • Store
    Task
    references, cancel in
    viewDidDisappear
    — not
    deinit
  • Check
    Task.isCancelled
    before UI updates after
    await
  • Task.detached
    does NOT inherit actor isolation — explicit
    MainActor.run
    needed for UI
  • Never call
    DispatchQueue.main.sync
    from background — use
    await MainActor.run
  • UIViewController
    默认是
    @MainActor
    — 所有子类方法隐式运行在主线程
  • 存储Task引用,在
    viewDidDisappear
    中取消 — 不在
    deinit
    中取消
  • await
    后更新UI前检查
    Task.isCancelled
  • Task.detached
    不继承actor隔离 — UI操作需显式使用
    MainActor.run
  • 绝不能从后台线程调用
    DispatchQueue.main.sync
    — 使用
    await MainActor.run
    替代

UIKit–SwiftUI Interop

UIKit–SwiftUI互操作

  • UIHostingController: full child VC containment (
    addChild
    addSubview
    didMove
    ), retain as stored property
  • sizingOptions = .intrinsicContentSize
    (iOS 16+) for Auto Layout containers
  • UIViewRepresentable: set mutable state in
    updateUIView
    , not
    makeUIView
    ; guard against update loops
  • UIHostingConfiguration (iOS 16+) for SwiftUI content in collection view cells
  • UIHostingController:使用完整的子VC容器化(
    addChild
    addSubview
    didMove
    ),并作为存储属性持有
  • iOS 16+:Auto Layout容器中设置
    sizingOptions = .intrinsicContentSize
  • UIViewRepresentable:在
    updateUIView
    中修改可变状态,而非
    makeUIView
    ;防止更新循环
  • iOS 16+:使用UIHostingConfiguration在集合视图单元格中嵌入SwiftUI内容

Image Loading

图片加载

  • Decoded bitmap size = width × height × 4 bytes (a 12MP photo = ~48MB RAM)
  • Downsample with ImageIO at display size — never load full bitmap and resize
  • iOS 15+: use
    byPreparingThumbnail(of:)
    or
    prepareForDisplay()
    for async decoding
  • Cell reuse: cancel Task in
    prepareForReuse
    , clear image, verify identity on completion
  • 解码后的位图大小 = 宽 × 高 × 4字节(一张12MP照片约占48MB内存)
  • 使用ImageIO按显示尺寸降采样 — 绝不加载完整位图后再缩放
  • iOS 15+:使用
    byPreparingThumbnail(of:)
    prepareForDisplay()
    进行异步解码
  • 单元格复用:在
    prepareForReuse
    中取消Task、清空图片、完成时验证身份

Keyboard & Scroll

键盘与滚动

  • Use
    UIKeyboardLayoutGuide
    (iOS 15+) — pin content bottom to
    view.keyboardLayoutGuide.topAnchor
  • iPad: set
    followsUndockedKeyboard = true
    for floating keyboards
  • Replace all manual keyboard notification handling with the layout guide
  • 使用
    UIKeyboardLayoutGuide
    (iOS 15+) — 将内容底部固定到
    view.keyboardLayoutGuide.topAnchor
  • iPad:为浮动键盘设置
    followsUndockedKeyboard = true
  • 用布局向导替代所有手动键盘通知监听

Adaptive Layout & Accessibility

自适应布局与无障碍支持

  • Use
    registerForTraitChanges
    (iOS 17+) instead of deprecated
    traitCollectionDidChange
  • Dynamic Type:
    UIFont.preferredFont(forTextStyle:)
    +
    adjustsFontForContentSizeCategory = true
  • Dark mode: use semantic colors (
    .label
    ,
    .systemBackground
    ); re-resolve CGColor on trait changes
  • VoiceOver: set
    accessibilityLabel
    ,
    accessibilityTraits
    ,
    accessibilityHint
    on custom views
  • Use
    UIAccessibilityCustomAction
    for complex list item actions
  • 使用
    registerForTraitChanges
    (iOS 17+)替代已废弃的
    traitCollectionDidChange
  • 动态字体:使用
    UIFont.preferredFont(forTextStyle:)
    +
    adjustsFontForContentSizeCategory = true
  • 深色模式:使用语义化颜色(
    .label
    .systemBackground
    );特性变化时重新解析CGColor
  • VoiceOver:为自定义视图设置
    accessibilityLabel
    accessibilityTraits
    accessibilityHint
  • 复杂列表项操作使用
    UIAccessibilityCustomAction

Quick Reference

速查参考

View Controller Lifecycle Method Selection

视图控制器生命周期方法选择

MethodUse For
viewDidLoad
One-time setup: subviews, constraints, delegates
viewIsAppearing
Geometry-dependent work, trait-based layout, scroll-to-item
viewWillAppear
Transition coordinator animations only
viewDidLayoutSubviews
Lightweight layer frame adjustments (fires multiple times)
viewDidAppear
Start animations, analytics, post-appearance work
viewWillDisappear
Cancel tasks, invalidate timers, save state
viewDidDisappear
Final cleanup, cancel background work
方法适用场景
viewDidLoad
一次性初始化:添加子视图、设置约束、委托配置
viewIsAppearing
几何依赖操作、基于特性的布局、滚动到指定项
viewWillAppear
仅用于转场协调器动画
viewDidLayoutSubviews
轻量级图层帧调整(会触发多次)
viewDidAppear
启动动画、统计上报、转场后操作
viewWillDisappear
取消任务、失效Timer、保存状态
viewDidDisappear
最终清理、取消后台任务

Animation API Selection

动画API选择

APIBest ForInteractiveOff Main Thread
UIView.animate
Simple one-shot changesNoNo
UIViewPropertyAnimator
Gesture-driven, interruptibleYesNo
CABasicAnimation
Layer properties, 3D transformsLimitedYes (Render Server)
API最佳适用场景可交互后台线程执行
UIView.animate
简单的一次性变化
UIViewPropertyAnimator
手势驱动、可中断动画
CABasicAnimation
图层属性、3D变换有限支持是(渲染服务器)

Deprecated → Modern API Replacements

废弃API → 现代API替代

Deprecated / LegacyModern ReplacementSince
traitCollectionDidChange
registerForTraitChanges(_:handler:)
iOS 17
Keyboard notifications
UIKeyboardLayoutGuide
iOS 15
cell.textLabel
/
detailTextLabel
UIListContentConfiguration
iOS 14
register
+ string dequeue
UICollectionView.CellRegistration
iOS 14
reloadItems
on snapshot
reconfigureItems
iOS 15
barTintColor
/
isTranslucent
UINavigationBarAppearance
(4 slots)
iOS 13
UICollectionViewFlowLayout
(complex)
UICollectionViewCompositionalLayout
iOS 13
Manual
layoutIfNeeded()
in animations
.flushUpdates
option
iOS 26
Legacy app lifecycle
UIScene
+
SceneDelegate
Mandatory iOS 26
ObservableObject
+ manual invalidation
@Observable
+
UIObservationTrackingEnabled
iOS 18
废弃/旧版API现代替代方案最低iOS版本
traitCollectionDidChange
registerForTraitChanges(_:handler:)
iOS 17
键盘通知
UIKeyboardLayoutGuide
iOS 15
cell.textLabel
/
detailTextLabel
UIListContentConfiguration
iOS 14
register
+ 字符串复用标识
UICollectionView.CellRegistration
iOS 14
快照更新使用
reloadItems
reconfigureItems
iOS 15
barTintColor
/
isTranslucent
UINavigationBarAppearance
(4个插槽)
iOS 13
复杂布局使用
UICollectionViewFlowLayout
UICollectionViewCompositionalLayout
iOS 13
动画中手动调用
layoutIfNeeded()
.flushUpdates
选项
iOS 26
旧版应用生命周期
UIScene
+
SceneDelegate
iOS 26强制要求
ObservableObject
+ 手动失效
@Observable
+
UIObservationTrackingEnabled
iOS 18

Review Checklist

评审检查清单

View Controller Lifecycle

视图控制器生命周期

  • viewDidLoad
    contains NO geometry-dependent work
  • Geometry/trait work is in
    viewIsAppearing
    , not
    viewWillAppear
  • Every lifecycle override calls
    super
  • Child VC uses correct containment sequence
  • deinit
    is implemented for leak verification during development
  • viewDidLoad
    中无几何依赖操作
  • 几何/特性相关操作在
    viewIsAppearing
    中,而非
    viewWillAppear
  • 所有生命周期重写方法都调用了
    super
  • 子VC使用正确的容器化顺序
  • 开发阶段实现
    deinit
    用于泄漏验证

Auto Layout

Auto Layout

  • translatesAutoresizingMaskIntoConstraints = false
    on all programmatic views
  • Constraints activated via
    NSLayoutConstraint.activate([])
  • No constraint removal/recreation — using
    isActive
    toggle or
    .constant
    modification
  • No priority changes from/to
    .required
    (1000) at runtime
  • No
    setNeedsLayout()
    inside
    layoutSubviews
    or
    viewDidLayoutSubviews
    (infinite loop)
  • Constraint identifiers set for debugging
  • 所有代码创建的视图都设置了
    translatesAutoresizingMaskIntoConstraints = false
  • 通过
    NSLayoutConstraint.activate([])
    激活约束
  • 无约束删除/重建 — 使用
    isActive
    切换或
    .constant
    修改
  • 运行时无优先级至/从
    .required
    (1000)的变更
  • layoutSubviews
    viewDidLayoutSubviews
    中无
    setNeedsLayout()
    (避免无限循环)
  • 约束设置了标识符用于调试

Collection Views

集合视图

  • Using diffable data source with stable identifiers (not full model structs)
  • reconfigureItems
    for content updates, not
    reloadItems
  • CellRegistration
    instead of string-based register/dequeue
  • UIContentConfiguration
    instead of deprecated cell properties
  • No duplicate identifiers in snapshot (
    BUG_IN_CLIENT
    crash)
  • Self-sizing cells have unambiguous top-to-bottom constraint chain
  • 使用差分数据源并搭配稳定标识符(非完整模型结构体)
  • 内容更新使用
    reconfigureItems
    ,而非
    reloadItems
  • 使用
    CellRegistration
    替代字符串式的注册/复用
  • 使用
    UIContentConfiguration
    替代已废弃的单元格属性
  • 快照中无重复标识符(避免
    BUG_IN_CLIENT
    崩溃)
  • 自调整单元格有明确的从上到下约束链

Navigation

导航

  • All 4
    UINavigationBarAppearance
    slots configured
  • Appearance set on
    navigationItem
    in
    viewDidLoad
    , not
    navigationBar
    in
    viewWillAppear
  • Concurrent transition guard in place
  • prefersLargeTitles
    set once;
    largeTitleDisplayMode
    per VC
  • 配置了全部4个
    UINavigationBarAppearance
    插槽
  • viewDidLoad
    中为
    navigationItem
    设置外观,而非在
    viewWillAppear
    中设置
    navigationBar
  • 存在并发转场防护
  • prefersLargeTitles
    仅设置一次;每个VC单独设置
    largeTitleDisplayMode

Animation

动画

  • Correct API chosen for use case (animate vs PropertyAnimator vs CA)
  • UIViewPropertyAnimator
    state machine respected
  • Constraint animation uses correct pattern (flush → update → animate)
  • CAAnimation
    sets model value before adding animation
  • Completion handlers check
    finished
    parameter
  • 根据场景选择了正确的API(animate/PropertyAnimator/CA)
  • 遵循
    UIViewPropertyAnimator
    状态机规则
  • 约束动画使用正确模式(刷新 → 更新 → 动画)
  • CAAnimation
    在添加动画前设置了模型值
  • 完成回调检查了
    finished
    参数

Memory Management

内存管理

  • [weak self]
    in all escaping closures
  • Timers use block-based API with
    [weak self]
    ; invalidated in
    viewWillDisappear
  • Task references stored and cancelled in
    viewDidDisappear
  • CADisplayLink uses weak proxy pattern
  • Delegates declared as
    weak var
    on
    AnyObject
    -constrained protocol
  • No strong self re-capture in nested stored closures
  • 所有逃逸闭包都使用了
    [weak self]
  • Timer使用基于block的API并搭配
    [weak self]
    ;在
    viewWillDisappear
    中失效
  • Task引用被存储并在
    viewDidDisappear
    中取消
  • CADisplayLink使用弱代理模式
  • 委托声明为
    weak var
    且协议带有
    AnyObject
    约束
  • 嵌套存储闭包中无强引用self的重捕获

Concurrency

并发

  • Task.isCancelled
    checked after
    await
    before UI updates
  • No
    Task.detached
    for UI work without explicit
    MainActor.run
  • No redundant
    @MainActor
    on
    UIViewController
    subclasses (already inherited)
  • No
    DispatchQueue.main.sync
    from background
  • await
    后更新UI前检查了
    Task.isCancelled
  • UI相关工作使用
    Task.detached
    时显式添加了
    MainActor.run
  • UIViewController
    子类无冗余的
    @MainActor
    声明(已默认继承)
  • 无从后台线程调用
    DispatchQueue.main.sync
    的情况

Image Loading

图片加载

  • Images downsampled to display size (not loaded at full resolution)
  • Cell image loading: cancel in
    prepareForReuse
    , clear image, verify identity
  • NSCache
    sized by decoded bitmap bytes, not file size
  • 图片按显示尺寸降采样(未加载全分辨率)
  • 单元格图片加载:
    prepareForReuse
    中取消、清空图片、完成时验证身份
  • NSCache
    按解码后的位图字节数限制大小,而非文件大小

UIKit–SwiftUI Interop

UIKit–SwiftUI互操作

  • UIHostingController
    retained as stored property (not local variable)
  • UIHostingController
    uses full child VC containment (
    addChild
    addSubview
    didMove
    )
  • updateUIView
    guards against infinite update loops with equality checks
  • UIHostingController
    作为存储属性持有(非局部变量)
  • UIHostingController
    使用完整的子VC容器化步骤(
    addChild
    addSubview
    didMove
  • updateUIView
    通过相等性检查防止无限更新循环

Keyboard

键盘

  • Using
    UIKeyboardLayoutGuide
    (iOS 15+) instead of keyboard notifications
  • iPad:
    followsUndockedKeyboard = true
    on the layout guide
  • 使用
    UIKeyboardLayoutGuide
    (iOS 15+)替代键盘通知
  • iPad:布局向导设置了
    followsUndockedKeyboard = true

Adaptive & Accessibility

自适应与无障碍

  • registerForTraitChanges
    (iOS 17+) instead of
    traitCollectionDidChange
  • Dynamic Type:
    preferredFont
    +
    adjustsFontForContentSizeCategory = true
  • CGColor properties re-resolved on trait changes (layer.borderColor, shadowColor)
  • Custom views have
    accessibilityLabel
    and
    accessibilityTraits
  • UIAccessibilityCustomAction
    for complex list item actions
  • 使用
    registerForTraitChanges
    (iOS 17+)替代
    traitCollectionDidChange
  • 动态字体:使用
    preferredFont
    +
    adjustsFontForContentSizeCategory = true
  • CGColor属性在特性变化时重新解析(layer.borderColor、shadowColor)
  • 自定义视图设置了
    accessibilityLabel
    accessibilityTraits
  • 复杂列表项操作使用
    UIAccessibilityCustomAction

Modern APIs (iOS 26+)

现代API(iOS 26+)

  • #available
    guards with sensible fallbacks for iOS 26+ features
  • UIScene
    lifecycle adopted (mandatory for iOS 26 SDK)
  • UIObservationTrackingEnabled
    considered for iOS 18+ targets
  • iOS 26+特性使用
    #available
    隔离并提供合理降级方案
  • 已适配
    UIScene
    生命周期(iOS 26 SDK强制要求)
  • iOS 18+目标考虑使用
    UIObservationTrackingEnabled

References

参考文档

  • references/view-controller-lifecycle.md
    — Lifecycle ordering, viewIsAppearing, child VC containment
  • references/auto-layout.md
    — Batch activation, constraint churn, priority, animation, debugging
  • references/modern-collection-views.md
    — Diffable data sources, compositional layout, CellRegistration
  • references/cell-configuration.md
    — UIContentConfiguration, UIBackgroundConfiguration, configurationUpdateHandler
  • references/list-performance.md
    — Prefetching, cell reuse, reconfigureItems, scroll performance
  • references/navigation-patterns.md
    — Bar appearance, concurrent transitions, large titles, deep links
  • references/animation-patterns.md
    — UIView.animate, UIViewPropertyAnimator, CAAnimation, springs
  • references/memory-management.md
    — Retain cycles, [weak self], Timer/CADisplayLink/nested closure traps
  • references/concurrency-main-thread.md
    — @MainActor, Task lifecycle, Swift 6, GCD migration
  • references/uikit-swiftui-interop.md
    — UIHostingController, UIViewRepresentable, sizing, state bridging
  • references/image-loading.md
    — Downsampling, decoded bitmap math, cell reuse race condition
  • references/keyboard-scroll.md
    — UIKeyboardLayoutGuide, scroll view insets, iPad floating keyboard
  • references/adaptive-appearance.md
    — Trait changes, Dynamic Type, dark mode, VoiceOver, accessibility
  • references/modern-uikit-apis.md
    — Observation framework, updateProperties(), .flushUpdates, UIScene, Liquid Glass
  • references/view-controller-lifecycle.md
    — 生命周期顺序、viewIsAppearing、子VC容器化
  • references/auto-layout.md
    — 批量激活、约束频繁重建、优先级、动画、调试
  • references/modern-collection-views.md
    — 差分数据源、组合布局、CellRegistration
  • references/cell-configuration.md
    — UIContentConfiguration、UIBackgroundConfiguration、configurationUpdateHandler
  • references/list-performance.md
    — 预加载、单元格复用、reconfigureItems、滚动性能
  • references/navigation-patterns.md
    — 导航栏外观、并发转场、大标题、深度链接
  • references/animation-patterns.md
    — UIView.animate、UIViewPropertyAnimator、CAAnimation、弹簧动画
  • references/memory-management.md
    — 循环引用、[weak self]、Timer/CADisplayLink/嵌套闭包陷阱
  • references/concurrency-main-thread.md
    — @MainActor、Task生命周期、Swift 6、GCD迁移
  • references/uikit-swiftui-interop.md
    — UIHostingController、UIViewRepresentable、尺寸设置、状态桥接
  • references/image-loading.md
    — 降采样、解码位图计算、单元格复用竞争条件
  • references/keyboard-scroll.md
    — UIKeyboardLayoutGuide、滚动视图内边距、iPad浮动键盘
  • references/adaptive-appearance.md
    — 特性变化、动态字体、深色模式、VoiceOver、无障碍支持
  • references/modern-uikit-apis.md
    — Observation框架、updateProperties()、.flushUpdates、UIScene、Liquid Glass

Philosophy

设计理念

This skill focuses on facts and best practices, not architectural opinions:
  • We don't enforce specific architectures (e.g., MVVM, VIPER, Coordinator)
  • We do encourage separating business logic for testability
  • We optimize for correctness first, then performance
  • We follow Apple's documented APIs and Human Interface Guidelines
  • We use "suggest" or "consider" for optional optimizations
  • We use "always" or "never" only for correctness issues
本技能聚焦于事实与最佳实践,而非架构偏好:
  • 不强制特定架构(如MVVM、VIPER、Coordinator)
  • 但鼓励分离业务逻辑以提升可测试性
  • 优先保证正确性,其次优化性能
  • 遵循苹果官方文档API和人机界面指南
  • 可选优化使用"建议"或"考虑"表述
  • 仅在正确性问题上使用"必须"或"绝不"表述",