美文网首页Swift大法好
Swift实现一个任务队列

Swift实现一个任务队列

作者: HarriesChen | 来源:发表于2016-03-11 07:50 被阅读1763次

这几天项目中需要用到离线请求,于是我就想到了利用队列来实现这个功能,首先这个队列需要的功能如下。

  • 队列能够添加任务
  • 队列能够被持久化到本地(从本地解析到内存)
  • 任务之间可以有依赖关系
  • 任务失败能够自动重试,可以设置重试次数

明确了需求以后就可以开干了。说到队列,我立马想到了FIFO的队列,也就是先进先出的队列,与栈的模型刚好反过来。iOS中并没有现在的队列数据结构可以用,但是iOS里面有一个东西叫做NSOperationQueue这货不是一个普通的队列,他的功能十分的强大,能够处理并发的操作,是苹果在cocoa层对多线程的一层封装。他有一个属性叫做maxConcurrentOperationCount,这个指定了能够有多少个任务能够在同一时间被执行,如果大于1那么就是并行的队列,如果等于1就是串行的队列。这个模型就像一间房子,里面有很多人,maxConcurrentOperationCount就是门的数量,门越多可以同时出去的人就越多,还有就是如果人的地位越高,也就是说任务的优先级越高的话是可以先出去的。

那么我们就通过改造NSOperationQueue来实现我们自己的队列。

首先我们继承NSOperationQueue来新建一个类Queue

public class Queue: NSOperationQueue {
    ...
}

队列有一些基本的属性。比如说任务的名字,最大并发数量,最大重试次数等。

/// the max times of retries when the task failing
    public let maxRetries: Int//最大重试次数
    var taskCallbacks = [String: TaskCallBack]()存放任务执行方法的数组
    var taskList = [String: QueueTask]()队列任务数组
    let serializationProvider: QueueSerializationProvider?//序列化助手
    let logProvider: QueueLogProvider?//log助手
    
    public required init(queueName: String, maxConcurrency: Int = 1,
        maxRetries: Int = 5,
        serializationProvider: QueueSerializationProvider? = nil,
        logProvider: QueueLogProvider? = nil) {
            
            self.maxRetries = maxRetries
            self.serializationProvider = serializationProvider
            self.logProvider = logProvider
            super.init()
            self.name = queueName
            self.maxConcurrentOperationCount = maxConcurrency
    }

然后继承NSOperation来新建一个QueueTask

任务也有一些一些基本的属性,比如说所属队列,任务ID,任务类型,这里通过任务类型来对任务进行分组,让同一组的任务采用相同的处理方法。


public class QueueTask: NSOperation {
    public let queue: Queue
    public var taskID: String
    public var taskType: String
    public var retries: Int
    public let created: NSDate
    public var started: NSDate?
    public var userInfo: AnyObject?
}

现在最基本的样子已经有了,现在有了任务和队列,那么下一步就需要把任务添加到队列里面。
这里我们来重写NSOperationQueueaddOperation方法,

/**
     add Queue task to the queue and it will automaticly invoke the start method
     
     - parameter op: Queuetask
     */
    public override func addOperation(op: NSOperation) {
        if let task = op as? QueueTask {
            taskList[task.taskID] = task
            print(taskList)
        }
        super.addOperation(op)
    }

这里将任务添加到了NSOperationQueue同时也加到了taskList里面,任务完成之后会从里面移除,这里这样做主要是讲任务直接持久化到本地,只有在任务真正完成之后才会被移除,这样即使中间退出了应用任务也不会丢失,下次再打开应用的时候会自动的从本地把让任务加载到队列之中。这个在处理一些离线网络请求的场景的时候很有帮助。在离线情况下对本地数据进行操作,相应的网络请求会暂存在队列之中。等待网络恢复之后再进行请求。

这里注意到addOperation方法执行之后任务会直接进去pending状态,相当于自动调用了Operation的start方法。

这里可以看到Queue中有这么一个方法,根据任务类型来查找不同的执行方法。

func runTask(task: QueueTask) {
        if let callback = taskCallbacks[task.taskType] {
             callback(task)
        } else {
            print("no callback registerd for task")
        }
    }

完成之后会从队列中被移除。

func taskComplete(op: NSOperation) {
        if let task = op as? QueueTask {
            taskList.removeValueForKey(task.taskID)
        }
    }

具体的代码见Github

相关文章

网友评论

    本文标题:Swift实现一个任务队列

    本文链接:https://www.haomeiwen.com/subject/oqotlttx.html