阅读视图

发现新文章,点击刷新页面。

iOS开发-适配XCode26、iOS26

1、核心特性

@Observable Object

UIKit 支持 @Observable 类型;数据(属性值)变更时,UI 自动更新;提升开发效率,减少手动刷新代码。

updateProperties

UIViewController 和 UIView 新增 updateProperties() 方法;通过修改属性值直接更新 UI

2、UI控件

导航栏

UINavigationItem 和 UIBarButtonItem 新增功能;转场效果 zoom 的触发条件扩展至 UIBarButtonItem

tabbbar栏

UITabBarController 新增 tabBarMinimizeBehavior 属性(类型:UITabBarController.MinimizeBehavior),用于设置 TabBar 最小化时的行为

玻璃风格

UIVisualEffectView 新增 UIGlassEffect 和 UIGlassContainerEffect, 符合 Liquid Glass 风格的视觉效果

按钮

新增 Liquid Glass 风格配置方法

UIView

新增 cornerConfiguration 属性(类型:UICornerConfiguration),用于设置圆角并支持动画

UISlider

新增拖拽时的样式设置, 支持在滑轨上添加刻度

UIImageView

Symbol Animations 新增动画效果:drawOn 和 drawOff

通知系统
  • UIKit 引入强类型通知
  • 提供类型安全和并发安全性
  • 不再使用基于字符串的标识符
  • 不再通过 userInfo 字典传递数据
文件

UIScene Open File

  • 应用内可调用系统功能
  • 将不支持的文件格式交给其他 App 打开
  • iOS 26 后可轻松实现跨应用文件打开

编译问题

  • 编译链接错误:ld: Assertion failed: (it != _dylibToOrdinal.end()), function dylibToOrdinal, file OutputFile.cpp, line 5184

解决:

进入 Target 的 Build Settings 标签: 选中 Target → Build Settings → 搜索 Other Linker Flags。 手动修改链接参数: 点击 Other Linker Flags,首先移除:

-ld64 
-ld_classic

添加:

-Xlinker 
-dead_strip
-Xlinker 
-allow_dead_duplicates

Swift多线程方案-Concurrency

简介

Swift Concurrency(async/await)是从 Swift 5.5 开始引入的一套并发编程模型,用来替代传统的回调(callback)、闭包嵌套(callback hell)、以及部分 GCD 使用场景,让异步代码写起来像同步代码一样清晰。

async / await

  • async:标记函数是 异步函数
  • await:表示 等待异步结果

本质:await 会“挂起当前任务”,但不会阻塞线程

示例

func fetchUser() async -> String {
    return "Tom"
}

func loadData() async {
    let user = await fetchUser()
    print(user)
}

async throws

支持错误处理(替代 callback 的 error)

enum NetworkError: Error {
    case failed
}

func fetchData() async throws -> String {
    throw NetworkError.failed
}

func load() async {
    do {
        let result = try await fetchData()
        print(result)
    } catch {
        print("error: \(error)")
    }
}

Task

Task 是并发执行的基本单位,类似 GCD 的 block,也是一个对象。

  • 普通 Task
Task {
    let data = await fetchUser()
    print(data)
}
let task = Task {
    ...
}
  • Detached Task(独立线程)
Task.detached {
    await doSomething()
}

区别:

Task:继承当前 Actor / 优先级 / 上下文

detached:完全独立(慎用)

async let

并发执行

场景:多个接口同时请求

func loadData() async {
    async let user = fetchUser()
    async let posts = fetchPosts()
    
    let result = await (user, posts)
    print(result)
}

TaskGroup

任务组

场景:批量请求 / 并发处理列表

func fetchAll() async {
    // 每个子任务返回值类型是 String
    await withTaskGroup(of: String.self) { group in
        // 动态创建多个异步任务 并发执行,逐个获取结果
        for i in 1...3 {
            group.addTask {
                return "Task \(i)"
            }
        }
        
        for await result in group {
            print(result)  // 打印每个任务的结果;顺序不确定-先完成先打印
        }
    }
}

生命周期:当代码执行完withTaskGroup { ... },会自动等待所有子任务完成,然后自动释放资源。另外,也能自动取消未完成任务(如果提前退出)。任一任务抛错 就会全部取消。

手动取消 group.cancelAll() ,如 退出页面

使用场景:

  • 动态任务数量 (对比 async let - 任务数固定)
  • 适合列表/批量处理

1、批量接口请求

func fetchUsers(ids: [Int]) async -> [User] {
    var result: [User] = []
    
    await withTaskGroup(of: User.self) { group in
        for id in ids {
            group.addTask {
                return await fetchUser(id: id)
            }
        }
        
        for await user in group {
            result.append(user)
        }
    }
    
    return result
}

2、批量下载

func downloadImages(urls: [URL]) async -> [UIImage] {
    var images: [UIImage] = []
    
    await withTaskGroup(of: UIImage?.self) { group in
        for url in urls {
            group.addTask {
                return try? await downloadImage(url: url)
            }
        }
        
        for await img in group {
            if let img = img {
                images.append(img)
            }
        }
    }
    
    return images
}

3、并发计算任务(CPU)

func processData(items: [Int]) async {
    await withTaskGroup(of: Void.self) { group in
        for item in items {
            group.addTask {
                heavyWork(item)
            }
        }
    }
}

4、限制最大并发数(手动处理)

func fetchWithLimit(ids: [Int]) async {
    let maxConcurrent = 2
    await withTaskGroup(of: String.self) { group in
        var iterator = ids.makeIterator()
        // 先启动前 N 个任务
        for _ in 0..<maxConcurrent {
            if let id = iterator.next() {
                group.addTask {
                    return await fetchUser(id: id)
                }
            }
        }
        // 每完成一个,就补一个
        for await result in group {
            print(result)
            if let nextId = iterator.next() {
                group.addTask {
                    return await fetchUser(id: nextId)
                }
            }
        }
    }
}

Actor

线程安全方案

用于解决数据竞争问题(替代锁)

actor Counter {
    private var value = 0
    
    func increment() {
        value += 1
    }
    
    func getValue() -> Int {
        return value
    }
}
let counter = Counter()

Task {
    await counter.increment()
    let v = await counter.getValue()
    print(v)
}

Actor = 自动串行队列 + 数据隔离

对比

方案 问题
NSLock 易死锁
DispatchQueue 需要手动管理
Actor 天然安全

实战应用场景

  • 网络请求
func fetchUser() async -> User { ... }
func fetchPosts() async -> [Post] { ... }

func load() async {
    let user = await fetchUser()
    let posts = await fetchPosts()
}

——对比旧方案

fetchUser { result in
    fetchPosts { posts in
        // 嵌套地狱
    }
}
  • 多个接口并发请求

多个请求任务并行执行,等待异步结果

func loadPage() async {
    async let banner = fetchBanner()
    async let list = fetchList()
    async let profile = fetchProfile()
    
    let (b, l, p) = await (banner, list, profile)
}
  • 主线程更新UI
func loadData() {
    Task {
        let data = await fetchData()
        
        await MainActor.run {
            self.label.text = data
        }
    }
}

或 使用@MainActor

@MainActor
func updateUI() {
    label.text = "Hello"
}
  • 取消任务
let task = Task {
    let data = await fetchData()
}

task.cancel()
  • 图片加载
func downloadImage(url: URL) async throws -> UIImage {
    let (data, _) = try await URLSession.shared.data(from: url)
    return UIImage(data: data)!
}
let task = Task {
    let image = try await downloadImage(url: url)
    cell.imageView.image = image
}

注意:需要处理 cell 复用问题(取消任务)-》 避免图片错位

override func prepareForReuse() {
    task?.cancel()
}
  • 顺序依赖
func process() async {
    let token = await login()
    let data = await fetchData(token: token)
    let result = await parse(data)
}

对比

方案 特点
GCD 底层强,但难维护
Operation 可控但复杂
async/await 简洁 + 可读性强

本质: •GCD:你管理线程 •async/await:系统帮你调度

总结

Swift Concurrency 本质就是:

用“同步写法”写“异步代码”,并且保证线程安全

❌