
主要变更: 1. 新增 EPImageUploader.swift 和 EPProgressHUD.swift,提供图片批量上传和进度显示功能。 2. 新建 EPMomentAPISwiftHelper.swift,封装动态 API 的 Swift 版本。 3. 更新 EPMomentPublishViewController,集成新上传功能并实现发布成功通知。 4. 创建多个文档,包括实施报告、检查清单和快速使用指南,详细记录功能实现和使用方法。 5. 更新 Bridging Header,确保 Swift 和 Objective-C 代码的互操作性。 此功能旨在提升用户体验,简化动态发布流程,并提供清晰的文档支持。
164 lines
6.1 KiB
Swift
164 lines
6.1 KiB
Swift
//
|
||
// EPImageUploader.swift
|
||
// YuMi
|
||
//
|
||
// Created by AI on 2025-10-11.
|
||
//
|
||
|
||
import UIKit
|
||
import Foundation
|
||
|
||
/// 图片批量上传工具(纯 Swift 内部类,直接使用 QCloudCOSXML SDK)
|
||
/// 不对外暴露,由 EPSDKManager 内部调用
|
||
class EPImageUploader {
|
||
|
||
init() {}
|
||
|
||
/// 批量上传图片(内部方法)
|
||
/// - Parameters:
|
||
/// - images: 要上传的图片数组
|
||
/// - bucket: QCloud bucket 名称
|
||
/// - customDomain: 自定义域名
|
||
/// - progress: 进度回调 (已上传数, 总数)
|
||
/// - success: 成功回调
|
||
/// - failure: 失败回调
|
||
func performBatchUpload(
|
||
_ images: [UIImage],
|
||
bucket: String,
|
||
customDomain: String,
|
||
progress: @escaping (Int, Int) -> Void,
|
||
success: @escaping ([[String: Any]]) -> Void,
|
||
failure: @escaping (String) -> Void
|
||
) {
|
||
let total = images.count
|
||
let queue = DispatchQueue(label: "com.yumi.imageupload", attributes: .concurrent)
|
||
let semaphore = DispatchSemaphore(value: 3) // 最多同时上传 3 张
|
||
var uploadedCount = 0
|
||
var resultList: [[String: Any]] = []
|
||
var hasError = false
|
||
let lock = NSLock()
|
||
|
||
for (_, image) in images.enumerated() {
|
||
queue.async {
|
||
semaphore.wait()
|
||
|
||
// 检查是否已经失败
|
||
lock.lock()
|
||
if hasError {
|
||
lock.unlock()
|
||
semaphore.signal()
|
||
return
|
||
}
|
||
lock.unlock()
|
||
|
||
// 压缩图片
|
||
guard let imageData = image.jpegData(compressionQuality: 0.5) else {
|
||
lock.lock()
|
||
hasError = true
|
||
lock.unlock()
|
||
semaphore.signal()
|
||
DispatchQueue.main.async {
|
||
failure("图片压缩失败")
|
||
}
|
||
return
|
||
}
|
||
|
||
// 获取图片格式
|
||
let format = UIImage.getImageType(withImageData: imageData) ?? "jpeg"
|
||
|
||
// 生成文件名
|
||
let uuid = NSString.createUUID()
|
||
let fileName = "image/\(uuid).\(format)"
|
||
|
||
// 直接使用 QCloud SDK 上传
|
||
let request = QCloudCOSXMLUploadObjectRequest<AnyObject>()
|
||
request.bucket = bucket
|
||
request.object = fileName
|
||
request.body = imageData as NSData
|
||
|
||
// 监听上传进度(可选)
|
||
request.sendProcessBlock = { bytesSent, totalBytesSent, totalBytesExpectedToSend in
|
||
// 单个文件的上传进度(当前不使用)
|
||
}
|
||
|
||
// 监听上传结果
|
||
request.finishBlock = { [weak self] result, error in
|
||
guard let self = self else {
|
||
semaphore.signal()
|
||
return
|
||
}
|
||
|
||
if let error = error {
|
||
// 上传失败
|
||
lock.lock()
|
||
if !hasError {
|
||
hasError = true
|
||
lock.unlock()
|
||
semaphore.signal()
|
||
DispatchQueue.main.async {
|
||
failure(error.localizedDescription)
|
||
}
|
||
} else {
|
||
lock.unlock()
|
||
semaphore.signal()
|
||
}
|
||
} else if let result = result as? QCloudUploadObjectResult {
|
||
// 上传成功
|
||
lock.lock()
|
||
if !hasError {
|
||
uploadedCount += 1
|
||
|
||
// 解析上传 URL(参考 UploadFile.m line 217-223)
|
||
let uploadedURL = self.parseUploadURL(result.location, customDomain: customDomain)
|
||
|
||
let imageInfo: [String: Any] = [
|
||
"resUrl": uploadedURL,
|
||
"width": image.size.width,
|
||
"height": image.size.height,
|
||
"format": format
|
||
]
|
||
resultList.append(imageInfo)
|
||
|
||
let currentUploaded = uploadedCount
|
||
lock.unlock()
|
||
|
||
// 进度回调
|
||
DispatchQueue.main.async {
|
||
progress(currentUploaded, total)
|
||
}
|
||
|
||
// 全部完成
|
||
if currentUploaded == total {
|
||
DispatchQueue.main.async {
|
||
success(resultList)
|
||
}
|
||
}
|
||
} else {
|
||
lock.unlock()
|
||
}
|
||
semaphore.signal()
|
||
} else {
|
||
semaphore.signal()
|
||
}
|
||
}
|
||
|
||
// 执行上传
|
||
QCloudCOSTransferMangerService.defaultCOSTransferManager().uploadObject(request)
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 解析上传返回的 URL(参考 UploadFile.m line 217-223)
|
||
/// - Parameters:
|
||
/// - location: QCloud 返回的原始 URL
|
||
/// - customDomain: 自定义域名
|
||
/// - Returns: 解析后的 URL
|
||
private func parseUploadURL(_ location: String, customDomain: String) -> String {
|
||
let components = location.components(separatedBy: ".com/")
|
||
if components.count == 2 {
|
||
return "\(customDomain)/\(components[1])"
|
||
}
|
||
return location
|
||
}
|
||
}
|