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
相关产品推荐
相关产品推荐

