iOS(Swift) TaskProtocol异步任务队列

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS(Swift) TaskProtocol异步任务队列相关的知识,希望对你有一定的参考价值。

参考技术A 昨天做需求时,一个简单的需求,一个动画展示,在动画展示几秒后,移除动画,然后我在 动画完成时completion写了个 prepareForReuse 方法去重置数据.但是冲突点来了,这个动画是 View 动画,不能提前取消,所以导致 Completion会在下次的 show 动画中被执行,如果还没来的及prepareForReuse就调用 show,这样数据展示就会出问题.

利用 OperationQueue 维护任务队列,设置并发数为1,所有任务都由信号量控制并发

这个操作队列的实现队列qos 采用utility,这个 UI 任务有可能持续一段时间.

核心逻辑即为用CancellableBlockOperation包装一个operation, 内部用 DispatchSemaphore 控制该任务的结束时机,利用 operationQueue 并发1的机制,达到异步UI 任务顺序执行的逻辑.

因为这个 信号wait ,所以我们需要之前的 undeylingQueue 需要利用.global()

协议设计完成,可以看看实现
从现在开始,我们就可以摆脱动画的嵌套地狱了.只要在你想要实现的对象上实现 TaskProtocol ,即可使用

我设定4个动画逻辑,展示

如果用UIView 实现,逻辑嵌套会十分的麻烦,而且无法取消,所以,搞起来吧,兄dei~
异步任务基本也是每个 APP 必备的,以前都是手写 queue,昨天思考了下用协议实现,省去中间商赚差价.
不过,如非必要,还是不要大规模实现,平时思考下,真的需要异步时再考虑,CAAnimation, GroupAnimation 优先级应该都是要比这个任务队列要高,省性能一定也要考虑

iOS Swift CoreData 异步下载图片数据

【中文标题】iOS Swift CoreData 异步下载图片数据【英文标题】:iOS Swift CoreData Asynchronous Downloading of Image Data 【发布时间】:2015-01-19 14:25:56 【问题描述】:

作为一个对 Swift 和 CoreData 很陌生的人,我确信我的做法是错误的,希望有人能提供帮助。

背景:我正在通过 API 下载 JSON,并在 iPad 上的 CoreData 中本地缓存内容。作为该过程的一部分,我需要下载一个小图像缩略图,并将其存储在 CoreData 中(作为 Transformable)。

我在做:我的原始实现下载了图像并将它们保存到 CoreData,但是虽然它是从后台线程触发的(API 调用之后的回调),但图像的实际下载似乎导致应用挂起:

let data = NSData(contentsOfURL: imgURL)
if let imageData = data 
    coreDataEntity.thumbnail = imageData

我现在在做什么:我已经将我的代码更新为以下内容:

func downloadImage(url: NSURL, cdEntity: CoreDataEntity, moc: NSManagedObjectContext, handler: ((image: UIImage?, cdEntity: CoreDataEntity, moc: NSManagedObjectContext, NSError!) -> Void))

    var imageRequest: NSURLRequest = NSURLRequest(URL: url)
    NSURLConnection.sendAsynchronousRequest(imageRequest,
        queue: NSOperationQueue.mainQueue(),
        completionHandler: response, data, error in
             handler(image: UIImage(data: data), cdEntity: cdEntity, moc: moc, error)
    )


func setImage(image: UIImage?, cdEntity: CoreDataEntity, moc: NSManagedObjectContext, error: NSError?) 
    cdEntity.thumbnail = image
    save(moc)

然后我这样调用代码:

downloadImage(imgURL, coreDataEntity, moc,  (image, cdEntity, moc, error) -> Void in
    setImage(image, cdEntity, moc, error)
)

这样做,我注意到主线程上没有任何块。从设备检查 sqlite 文件,看起来数据设置正确,但图像未显示在 UI 中。

我的方法完全错误吗?如果不是,我如何通知 UI 核心数据模型已以导致刷新的方式更新?可以调用什么函数来更新表格/uicollectionview的特定行/单元格?

【问题讨论】:

"并在 CoreData 中将内容本地缓存到 iPad 上。"呃……为什么? URL 加载系统已经在为您处理缓存。如果您想将缓存的数据持久化到磁盘,您只需将其打开即可。请参阅NSURLCache 的文档。 我很高兴研究替代缓存选项,但指向图像(存储在 S3 上)的 URL 可能会随着新令牌的生成而发生变化以授予对它的访问权限。我的假设是这会使 NSURLCache 无效。 【参考方案1】:

    您的 NSURLConnection 的回调发生在主队列上。这是您的应用程序被锁定的原因之一。

    您的托管对象上下文(至少在您发布的代码中)没有遵循 Core Data 并发规则。您可以在线程限制(不幸的是,默认设置,已过时)和队列限制之间进行选择。

使用线程限制,您只能使用创建它的线程中的托管对象上下文。如果您在主线程(或队列)上创建托管对象上下文,则只能从那里使用它 - 因此您在该上下文上执行的任何 Core Data 操作都会阻塞主线程,进而阻塞 UI。

使用队列限制(几乎)任何对托管对象上下文的操作都必须通过performBlock:performBlockAndWait: 方法。入队的块在上下文的串行队列上执行。这比线程限制更不容易出错,并且自 iOS 5 以来一直是并发的推荐做法。

如果没有,我如何通知 UI 核心数据模型已以导致刷新的方式更新?可以调用什么函数来更新表格/uicollectionview的特定行/单元格?

这通常使用NSFetchedResultsController 来完成,它会观察托管对象上下文中与其获取请求相关的更改。一旦初始获取填充控制器,它将侦听影响获取请求指定的对象的上下文更改。当发生相关更改时,控制器会通过回调通知它的委托。

【讨论】:

以上是关于iOS(Swift) TaskProtocol异步任务队列的主要内容,如果未能解决你的问题,请参考以下文章

Xcode 8 / Swift 3 中的 iOS 异步单元测试(waitForExpectations 失败)

iOS - 在 Swift 中获取集合的异步属性的最佳实践

IOS Swift我如何从异步方法中获得价值[重复]

swift ios 10 异步或后台执行代码

iOS Swift CoreData 异步下载图片数据

在 iOS swift 中异步/并发/并行运行任务