Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Background image load api #1007

Merged
merged 36 commits into from
Jul 24, 2018

Conversation

wsdwsd0829
Copy link
Contributor

@wsdwsd0829 wsdwsd0829 commented Jul 4, 2018

Currently delegate methods are called on main.
We may want to deprecated those and introduce the calls on background thread?
The benefit is that user have flexibility to log time of image fetched to image displayed/decoded.
This is similar to NSURLSession's didReceive data.

Copy link
Member

@Adlai-Holler Adlai-Holler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be totally fine moving forward with this – we see the main thread getting pretty clogged e.g. during launch.

That said, does it make more sense to have a global property on ASNetworkImageNode @property (class) BOOL delegateCallbacksOnMainThread; // default YES?

As a matter of pure curiosity, what is the motivation behind this for your use case? It's worthwhile regardless but it might be worth knowing.

Finally, it may make sense to send these callbacks on a serial queue. Using a concurrent queue, for example, two load events could theoretically be delivered out-of-order (didFetch: and then didFailToFetch: when in fact the failure came before the success).

*
* @discussion Called on a background queue.
*/
- (void)imageNode:(ASNetworkImageNode *)imageNode didFetchImage:(UIImage *)image;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating ASNetworkImageLoadInfo objects is really cheap, so if we're revising this API I'd advocate for removing this method and only providing didFetchImage:info: and didFailFetchingWithError:.

If you choose to go that route, update the docs for didFetchImage:info: to remove the reference to this method.


/**
* Notification that the image node finished downloading an image.
*
* @param imageNode The sender.
* @param image The newly-loaded image.
*
* @discussion Called on a background queue.
* @discussion Called on a main queue.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Called on the main thread.

@wsdwsd0829
Copy link
Contributor Author

  1. +1 for @Property (class) BOOL delegateCallbacksOnMainThread; I was thinking to add an experiment flag instead, but seems an overkill.
  2. it's for logging purpose, to match ticks for existing image loading system (pre PRI).
  3. I did not get this, looks like didFetch & didFailToFetch are mutual exclusive?
  4. Dropped didFetchImage: to use info: only.

@TextureGroup TextureGroup deleted a comment Jul 12, 2018
@TextureGroup TextureGroup deleted a comment Jul 12, 2018
@Adlai-Holler
Copy link
Member

@wsdwsd0829 3 is a pretty fantastical case, but theoretically you could have the following sequence:

  • set URL to x
  • didFailToFetch: is enqueued
  • set URL to y
  • didFetch: is enqueued
  • didFailToFetch: is dequeued and the thread is put to sleep
  • didFetch: is dequeued and executed
  • didFailToFetch: thread wakes up and executes

From the observer's perspective, the first load succeeded and the second one failed, but in truth the order is reversed.

However, that risk is so unlikely and the proper solution would be to share a pool of serial queues, where each node gets assigned a queue, which isn't worth the extra effort.

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self class].delegateCallbacksOnMainThread = YES;
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can remove this since the variable is initialized to YES.

*
* @discussion Called on a background queue.
*/
- (void)imageNode:(ASNetworkImageNode *)imageNode didFailFetchingWithError:(NSError *)error;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that we have this flag, we can continue using the old methods and remove these.

We also need to update the documentation of the existing methods to say:

@discussion Called on the main thread if delegateCallbacksOnMainThread=YES (the default,) otherwise on a background thread.

Copy link
Contributor Author

@wsdwsd0829 wsdwsd0829 Jul 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought the goal is to remove the delegate to main ones eventually. If we use same call out block. Would it be harder handle the deprecate marks?
However, maybe your suggest is better and make code much cleaner, so I will go for it.

@wsdwsd0829
Copy link
Contributor Author

I see for 3, I was assuming user would only use one image node for one url. (I do not see a use case for one node with multiple urls). I suggest we postpone the work until we need it? ( current impl have the issue right?)

@Adlai-Holler
Copy link
Member

Adlai-Holler commented Jul 12, 2018 via email

/**
* The delegate will receive callbacks on main thread. Default to YES.
*/
@property (class) BOOL delegateCallbacksOnMainThread;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking of various names that might be good to establish a standard here - I wonder if "useMainThreadDelegateCallbacks" is any better?

@@ -426,6 +428,14 @@ - (void)didEnterPreloadState
[self _lazilyLoadImageIfNecessary];
}

+ (void)setDelegateCallbacksOnMainThread:(BOOL)delegateCallbacksOnMainThread {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Match file style with { on next line for all method definitions.

@@ -716,7 +726,7 @@ - (void)_lazilyLoadImageIfNecessary
strongSelf->_cacheSentinel++;

void (^calloutBlock)(ASNetworkImageNode *inst);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revert this whitespace change

@@ -85,6 +85,8 @@ @interface ASNetworkImageNode ()

@implementation ASNetworkImageNode

static BOOL _useMainThreadDelegateCallbacks = YES;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically this should be static std::atomic_bool _useMainThreadDelegateCallbacks(true) or some variant. The other code in here should be OK, since c++ defines the operators to implicitly do store/load.

In practice the risk is trivial. I approve either way – let's get this landed!

@TextureGroup TextureGroup deleted a comment Jul 19, 2018
@Adlai-Holler
Copy link
Member

@nguyenhuy @garrettmoon @maicki Would someone be willing to approve the build?

@maicki
Copy link
Contributor

maicki commented Jul 23, 2018

@Adlai-Holler You got it

@ghost
Copy link

ghost commented Jul 23, 2018

🚫 CI failed with log

@wsdwsd0829
Copy link
Contributor Author

wsdwsd0829 commented Jul 24, 2018 via email

@nguyenhuy
Copy link
Member

@wsdwsd0829 I've just triggered it manually. You have to modify "testable files", rather than markdown or json files, for the test suite to be run.

@wsdwsd0829
Copy link
Contributor Author

wsdwsd0829 commented Jul 24, 2018 via email

@nguyenhuy
Copy link
Member

For the record, CI passed on d6c133a but GH's stuck on the old failure. I'm gonna land this PR.

@nguyenhuy nguyenhuy merged commit 905c582 into TextureGroup:master Jul 24, 2018
mikezucc pushed a commit to mikezucc/Texture that referenced this pull request Oct 2, 2018
* fix SIMULATE_WEB_RESPONSE not imported TextureGroup#449

* Fix to make rangeMode update in right time

* remove uncessary assert

* add api to allow delegated calls in background.

* fix typo

* 1. Add class property to decide whether to send delegate callbacks on
main or background.
2. remove non-info api.

* Refactor.

* add ivar for class property.

* Donot use extra api.

* Refactor

* refactor

* revert to use let

* refactor

* make class property atomic.

* kick of new ci test.

* kick off new ci
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants