You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift调用MSGraph时,如何避免多层Completion Block传递结果与错误?

替代多层Completion Block的优化方案

1. 使用Swift Async/Await(推荐)

如果你的项目基于Swift 5.5+,这是最简洁的解决方案——完全不需要传递completion block,直接用异步函数语法把异步调用写成同步风格,错误和结果会自动通过throws和返回值向上传递。

改造MSGraph异步方法

MSGraph的Swift SDK已支持Async/Await(旧版本可升级适配),把原来的闭包调用改成异步函数:

func getEvents() async throws -> [MSGraphEvent] {
    let result = try await graphClient.me.events.get()
    return result.value ?? []
}

多层函数调用示例

原来需要每层传completion的函数链,现在可以直接写成:

// 顶层调用函数
func processUserEvents() async throws {
    let events = try await fetchUserEvents()
    // 处理事件的业务逻辑
}

// 中间层函数
func fetchUserEvents() async throws -> [MSGraphEvent] {
    let calendarId = try await getUserDefaultCalendarId()
    return try await getEventsForCalendar(calendarId: calendarId)
}

// 底层调用MSGraph的函数
func getUserDefaultCalendarId() async throws -> String {
    let calendar = try await graphClient.me.calendar.get()
    guard let id = calendar.id else {
        throw CustomError.missingCalendarId
    }
    return id
}

所有错误会通过throws自动向上抛出,调用方只需用try await捕获或处理错误,全程无需手动传递completion block。

2. 使用Combine框架

如果项目已在使用Combine,可以用Publisher传递结果和错误,每层函数返回对应的Publisher,通过链式调用替代completion传递。

改造MSGraph方法为Publisher

func getEventsPublisher() -> AnyPublisher<[MSGraphEvent], Error> {
    Future { promise in
        graphClient.me.events.get { result, error in
            if let error = error {
                promise(.failure(error))
            } else {
                promise(.success(result?.value ?? []))
            }
        }
    }
    .eraseToAnyPublisher()
}

多层链式调用

// 声明存储订阅的容器
private var cancellables = Set<AnyCancellable>()

func processEvents() {
    getUserDefaultCalendarIdPublisher()
        .flatMap { calendarId in
            self.getEventsForCalendarPublisher(calendarId: calendarId)
        }
        .sink(receiveCompletion: { completion in
            switch completion {
            case .failure(let error):
                // 统一处理错误
                print("事件处理失败: \(error)")
            case .finished:
                break
            }
        }, receiveValue: { events in
            // 处理事件结果
            print("获取到 \(events.count) 条事件")
        })
        .store(in: &cancellables)
}

func getUserDefaultCalendarIdPublisher() -> AnyPublisher<String, Error> {
    Future { promise in
        graphClient.me.calendar.get { calendar, error in
            if let error = error {
                promise(.failure(error))
            } else if let id = calendar?.id {
                promise(.success(id))
            } else {
                promise(.failure(CustomError.missingCalendarId))
            }
        }
    }
    .eraseToAnyPublisher()
}

通过Combine的流链式操作,结果和错误会自动在流中传递,无需每层手动传递completion。

3. 自定义Result回调封装(兼容旧版本)

如果无法使用Async/Await或Combine,可以封装统一的Result回调类型,减少重复代码:

// 定义统一的回调类型
typealias APICompletion<T> = (Result<T, Error>) -> Void

func getEvents(completion: APICompletion<[MSGraphEvent]>) {
    graphClient.me.events.get { result, error in
        if let error = error {
            completion(.failure(error))
        } else {
            completion(.success(result?.value ?? []))
        }
    }
}

func fetchUserEvents(completion: APICompletion<[MSGraphEvent]>) {
    getUserDefaultCalendarId { result in
        switch result {
        case .success(let calendarId):
            self.getEventsForCalendar(calendarId: calendarId, completion: completion)
        case .failure(let error):
            completion(.failure(error))
        }
    }
}

虽然仍基于回调,但通过统一的APICompletion简化了定义,错误可直接传递,无需每层重复包装。


内容的提问来源于stack exchange,提问作者tech_human

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 09:51:07