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

Swift中带泛型的可选返回类型网络请求实现问题

问题分析

当前代码存在两个核心问题:

  1. 泛型参数无法推断:编译器无法将OutgoingEvent的objectType与函数泛型T建立关联,导致无法自动推导T的类型。
  2. 类型不匹配:函数返回T?可选类型,但调用时直接赋值给非可选的User类型,引发类型转换错误。

解决方案

1. 重构枚举,强绑定事件与返回类型

将枚举改为关联值枚举,直接把返回类型作为事件的关联值,让编译器能明确每个事件对应的返回类型,从根源解决类型推断问题:

public enum OutgoingEvent {
    // 有返回值的事件,关联对应的Codable类型
    case user(User.Type)
    case identification(Identification.Type)
    // 无返回值的事件,关联Void.Type或单独定义
    case logout
    // ... 更多事件
    
    // 保留原始字符串标识(如果需要与服务器交互用)
    var rawValue: String {
        switch self {
        case .user: return "user"
        case .identification: return "identification"
        case .logout: return "logout"
        // ... 其他事件的rawValue
        }
    }
}

// 给枚举扩展计算属性,统一获取目标类型
extension OutgoingEvent {
    var targetType: Codable.Type? {
        switch self {
        case .user(let type): return type
        case .identification(let type): return type
        case .logout: return nil
        // ... 其他事件处理
        }
    }
}

2. 简化泛型函数实现

修改回调版和Async/Await版函数,利用枚举的关联值约束泛型类型:

回调版函数

func sendWithAck<T: Codable>(event: OutgoingEvent, data: [[String : Any]], completion: @escaping (Result<T?, Error>) -> ()) throws {
    // 检查当前事件是否有目标返回类型
    guard let targetType = event.targetType as? T.Type else {
        // 无返回类型的事件,直接返回nil
        completion(.success(nil))
        return
    }
    
    // 假设已获取服务器返回的result字典
    guard let decodedObject = try? decodeFromDict(object: result, type: targetType) else {
        completion(.failure(ServerCommunicationError.invalidDataFromServer("Could not decode result data.")))
        return
    }
    
    completion(.success(decodedObject))
}

Async/Await版函数

func sendWithAck<T: Codable>(event: OutgoingEvent, data: [[String : Any]]) async throws -> T? {
    return try await withCheckedThrowingContinuation { continuation in
        do {
            try sendWithAck(event: event, data: data) { result in
                continuation.resume(with: result)
            }
        } catch {
            continuation.resume(throwing: error)
        }
    }
}

3. 正确调用函数

现在编译器能从事件的关联值自动推断泛型类型,同时处理可选返回值:

有返回值的场景(如.user事件)

// 推荐用可选绑定处理返回值
if let user = try await ServerService.shared.sendWithAck(event: .user(User.self), data: [updateData]) {
    // 使用解码后的user对象
}

// 若确定服务器必然返回非nil值,可强制解包(谨慎使用)
let user: User = try await ServerService.shared.sendWithAck(event: .user(User.self), data: [updateData])!

无返回值的场景(如.logout事件)

// 直接调用忽略返回值即可
try await ServerService.shared.sendWithAck(event: .logout, data: [])

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 12:05:21