iOS Concurrency with GCD and Operations - Part 8: | Ray Wenderlich

Learn how to use the results from one Operation in another and specify that the second Operation shouldn't be executed until the first has completed.


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/3648-ios-concurrency-with-gcd-and-operations/lessons/8

hi, congratulations for tutorials, I have a question about the extension of AsyncOperation class.
in particular of:
isReady var,
why this is the only calling super ?.

hi Emanuele: actually, AsyncOperation’s cancel() also calls super, but that’s an erratum, mentioned in the forum comments.

We have to check super.isReady because it’s the Operation that the operation queue keeps track of, in terms of dependencies. So just because the AsyncOperation thinks it’s ready, doesn’t mean that any other operations it depends on have finished. Does that make sense?

Hi, Audrey!
Thanks for the great tutorials!

Have a question on Challenge:
Why don’t we call DispatchQueue.main.async in filter.completionBlock ?

i’ve got an error in runtime in one of several launches. And also why without calling main.async
image is set to the imageView but it’s not the main thread.

Thank you!

oops! because the original exercise was written in a playground, which doesn’t really need the main queue, and I forgot to fully adapt it to an app.

You’re absolutely right, it should be:

filter.completionBlock = {
    DispatchQueue.main.async {
        self.imageView.image = filter.outputImage
    }
}

It works anyway, without the main queue dispatch, because there’s nothing else happening in this app. It just takes a little longer to appear. If you were loading a table of images, the delays would be noticeable.

Thanks Alex!!

Hi Audrey,

Thanks for the great video.

I have a question regarding inputImage == .none, does it have the same effect as inputImage == nil?

And why I cannot use myClass == .none on my own defined class even if I use it in this way var myClass: MyClass?, unless I inherit MyClass from NSObject? Does something in NSObject do the tricks?

BR
Darwin

.none is one of the cases of the Optional enum.

Optional conforms to NilLiteralConvertible, which lets you test any object against nil.

Testing equality with .none requires the object to conform to Equatable, or to subclass NSObject, which conforms to NSObjectProtocol, so implements isEqual(_:).

So you can ask myClass == nil without doing anything special to MyClass, but you can’t test directly myClass == .none unless Xcode knows how to test equality for MyClass objects.

Why would you test == .none instead of == nil? it’s more direct, and Ben Dietzkis wrote a post explaining why he sometimes prefers it:

it’s actually recommended to check if something !=.None(nil`), if you are certain there’s a possibility an object may be empty

This is exactly what I have been trying to find a solution for. You nailed it, Audrey! Thanks so much!

thanks for posting! it’s exactly what we like to hear :smile:

Hi, thanks for the video.

I’m not complete understand why when we use protocol output image of ImageLoadOperation not nil as it was when we just addDependency at the beginning of the video.

Can you explain it with more detail?

Already realise it ))

1 Like

Hi there, I have a question about an asynchronous function which doesn’t tell you when it finishes:
collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
How can I encapsulate or dispatch it so that I can be notified when it finishes the scroll / animation?

Thanks in advance

hi Gianluigi: scroll views use a delegate to handle this; the collection view delegate subclasses scroll view delegate. The relevant delegate method is probably:

https://developer.apple.com/documentation/uikit/uiscrollviewdelegate/1619379-scrollviewdidendscrollinganimati

Hi Audrey! I have a question about passing data via the dependencies.

In a project I’ve moved all of that code into a computed property that looks like this:

var _input: String {  
  guard let provider = dependencies
          .filter({$0 is StringProvider})
          .first as? StringProvider
       else { return "No Provider"}

     return input ?? provider.provided

Given everything else is set up as I learned in your tutorials, it works in a playground. However when I do the same in an actual project, I get a EXC_BAD_ACCESS exception. IF I change the downcast to be a the operation instead of the protocol, it works. Any ideas on whats could be causing the exception in Xcode?

-C

@audrey Can you please help with this when you get a chance? Thank you - much appreciated! :]

hi Caleb

that sounds really mysterious …

there seems to be a typo in this? I’m not sure what you did that works:

Sorry about that, @audrey

If I change the guard statement to downcast to the operation type ProviderOperation vs the protocol type StringProvider it will compile and pass data.

To be clear:

guard let provider = dependencies.filter({$0 is StringProvider}).first as? ProviderOperation else {return} 
 // Success

guard let provider = dependencies.filter({$0 is StringProvider}).first as? StringProvider else {return}
// Unsuccessful

-C

hmmm did you mark ProviderOperation as conforming to StringProvider?

in my code, this is done as extensions but you can add it to the ProviderOperation class directly.

@Audrey
Yes. everything conforms as it should. The code complies, it just throws an exception. Weird right?

that it works in playgrounds is also weird … could be an Xcode bug you should report?

try this exception breakpoint trick from natasha the robot:
https://www.natashatherobot.com/xcode-debugging-trick/