{"id":40,"date":"2021-02-07T21:16:42","date_gmt":"2021-02-07T12:16:42","guid":{"rendered":"https:\/\/brevans.io\/?p=40"},"modified":"2021-02-11T20:52:54","modified_gmt":"2021-02-11T11:52:54","slug":"operation","status":"publish","type":"post","link":"https:\/\/brevans.io\/index.php\/2021\/02\/07\/operation\/","title":{"rendered":"Operation"},"content":{"rendered":"\n<p>How often do you see someone use <code>DispatchQueue<\/code>? Now how often do you see <code>Operation<\/code> and <code>OperationQueue<\/code>? I feel like the <code>Operation<\/code> class is severely underused in most apps. Granted, <code>DispatchQueue<\/code> works fine, and <code>Operation<\/code> is just a wrapper for Grand Central Dispatch, but that doesn&#8217;t mean much in the Swift world. After all, Swift is a High Level Language. If we use that same argument, we could be writing in C++ or Assembly directly. So let&#8217;s take a look at just what <code>Operation<\/code> can do.<\/p>\n\n\n\n<p>For starters, <code>DispatchQueue<\/code> doesn&#8217;t bode well for indentation. Once a few conditionals or loops appear the code starts looking more and more like a staircase:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>func doIt() {\n    DispatchQueue.global(qos: .background).async {\n        if thisCondition {\n            if thatCondition {\n                \/\/ Processing...\n            }\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<p>Unless you&#8217;re an Escher fan, I can&#8217;t imagine that looks great. So let&#8217;s start converting that <code>async<\/code> call into an <code>Operation<\/code>. Starting simply, we can use the pre-made <code>BlockOperation<\/code> All we need to do is call the initializer and pass in our code.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>func doIt() {\n    let operation = BlockOperation {\n        if thisCondition {\n            if thatCondition {\n                \/\/ Processing...\n            }\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<p>So\u2026 the code looks about the same, maybe a little bit more verbose than anything. And to top it off, this operation doesn&#8217;t even execute yet. In fact, even if we added <code>operation.start()<\/code> we wouldn&#8217;t be running asynchronously anyway. At this point, <code>Operation<\/code> is looking like <em>more work<\/em> than <code>DispatchQueue<\/code>.<\/p>\n\n\n\n<p>So let&#8217;s start using <code>Operation<\/code> the way it was meant to be, by moving the block into an <code>Operation<\/code> subclass itself. This is fairly simple, override <code>main()<\/code> and add a few checks for <code>isCancelled<\/code>. Why check <code>isCancelled<\/code>? Because an <code>Operation<\/code> can be cancelled, unlike a <code>DispatchQueue<\/code>. This is great for long running tasks that might not even end up needed by the time they are finished.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>class MyOperation: Operation {\n    override func main() {\n        guard !isCancelled else { return }\n\n        if thisCondition {\n            if thatCondition {\n                \/\/ Processing...\n            }\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<p>Note that we want to check <code>isCancelled<\/code> whenever we are going to take a bit of time to work. Loops are a great place to do this, and you might even think about using a good &#8216;ol <code>for<\/code> rather than <code>forEach<\/code> in those cases:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>for object in objectList {\n    guard !isCancelled else { return } \n    \/\/ Processing...\n}<\/code><\/pre>\n\n\n\n<p>Well, it&#8217;s been a bit of extra overhead, but let&#8217;s move back to the call site. Now we&#8217;re finally taken a step out of our staircase.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>func doIt() {\n    let operation = MyOperation()\n    if operation.isReady {\n        operation.start()\n    }\n}<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>In the above code, we <em>need<\/em> to check if the operation\u2019s <code>isReady<\/code>. Calling <code>start<\/code> before the operation is ready (or while it is already running) is counterintuitive and will cause a crash.<\/p><\/blockquote>\n\n\n\n<p>That looks much better. Of course, some operations will need data passed in. Since it is a subclass, we can add nice initializers and properties for setting the data. In fact, adding custom initializers will also make it easier to write tests, so win-win on that.<\/p>\n\n\n\n<p>Once <code>operation.start()<\/code> returns, the operation is already complete, and the data is ready to use. This is helpful for breaking up code into multiple classes, but running on the same thread as our current code is not what <code>DispatchQueue.async<\/code> is doing (usually).<\/p>\n\n\n\n<p>Fortunately, that is exactly why <code>OperationQueue<\/code>s exist. In the most basic implementation, we just need to instantiate the queue and add our operation. Remember to keep the queue around though.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>let operationQueue = OperationQueue()\n\nfunc doIt() {\n    let operation = MyOperation()\n    operationQueue.addOperation(operation)\n}<\/code><\/pre>\n\n\n\n<p>If we want to go even further, we can even set <code>OperationQueue<\/code>\u2019s <code>qualityOfService<\/code>. This performs a role similar to <code>.global(qos: .background)<\/code> and completes the conversion from the <code>DispatchQueue<\/code> example at the start of this article.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>let operationQueue: OperationQueue = {\n    let queue = OperationQueue()\n    queue.qualityOfService = .background\n    return queue\n}()\n\nfunc doIt() {\n    let operation = MyOperation()\n    operationQueue.addOperation(operation)\n}<\/code><\/pre>\n\n\n\n<p>At this point <code>DispatchQueue<\/code> has been replaced and we have split out our code into a separate, testable class. But what about callbacks and updating our UI? Fortunately, <code>Operation<\/code> has a <code>completionBlock<\/code> property that is automatically called by the queue! While this will introduce a block again, this block only cares about cleanup and after actions, and may not even be needed.<\/p>\n\n\n\n<p><strong>But wait there\u2019s more!<\/strong> What if we have multiple operations to complete? Where that would require calling <code>DispatchQueue.aysnc<\/code> a couple of times, our <code>OperationQueue<\/code> already takes care of that. Adding another operation with <code>addOperation(_:)<\/code> is all that needs to be done. In fact, these operations can even be run concurrently or in order(!) by setting <code>maxConcurrentOperationCount<\/code> on the queue.<\/p>\n\n\n\n<p>So I hope I&#8217;ve shown you some of the benefits of using <code>Operations<\/code> over straight <code>DispatchQueue<\/code> calls. We&#8217;re already using a high-level language, so how about we spend a little more time using high level constructs as well!<\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>*If you have any questions, comments, or corrections let me know on <a href=\"https:\/\/twitter.com\/brevansio\">Twitter<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>How often do you see someone use DispatchQueue? Now how often do you see Operation and OperationQueue? I feel like the Operation class is severely underused in most apps. Granted, DispatchQueue works fine, and Operation is just a wrapper for Grand Central Dispatch, but that doesn&#8217;t mean much in the Swift world. After all, Swift&hellip; <a class=\"more-link\" href=\"https:\/\/brevans.io\/index.php\/2021\/02\/07\/operation\/\">Continue reading <span class=\"screen-reader-text\">Operation<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-40","post","type-post","status-publish","format-standard","hentry","category-uncategorized","entry"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/brevans.io\/index.php\/wp-json\/wp\/v2\/posts\/40","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/brevans.io\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/brevans.io\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/brevans.io\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/brevans.io\/index.php\/wp-json\/wp\/v2\/comments?post=40"}],"version-history":[{"count":4,"href":"https:\/\/brevans.io\/index.php\/wp-json\/wp\/v2\/posts\/40\/revisions"}],"predecessor-version":[{"id":49,"href":"https:\/\/brevans.io\/index.php\/wp-json\/wp\/v2\/posts\/40\/revisions\/49"}],"wp:attachment":[{"href":"https:\/\/brevans.io\/index.php\/wp-json\/wp\/v2\/media?parent=40"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/brevans.io\/index.php\/wp-json\/wp\/v2\/categories?post=40"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/brevans.io\/index.php\/wp-json\/wp\/v2\/tags?post=40"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}