-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Use CoreDataStack
in MediaThumbnailService
#20294
Conversation
} | ||
let mediaService = MediaService(managedObjectContext: coreDataStack.mainContext) | ||
mediaService.getMediaWithID(mediaID, in: media.blog, success: { (loadedMedia) in | ||
onCompletion(loadedMedia, nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since a Media
object is leaked out of MediaService
's lifecycle(or MediaService.managedObjectContext
's to be exact), it's only safe to use the main context as the MediaService
instance's context.
/// | ||
/// - Note: Images may be downloaded and resized if required, avoid requesting multiple explicit preferredSizes | ||
/// as several images could be downloaded, resized, and cached, if there are several variations in size. | ||
/// | ||
@objc func thumbnailURL(forMedia media: Media, preferredSize: CGSize, onCompletion: @escaping OnThumbnailURL, onError: OnError?) { | ||
managedObjectContext.perform { | ||
let context = coreDataStack.mainContext |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using the main context here because this function only read the Media
instance, without changing it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, there is no time consuming work done in the block that's passed to the perform
function, all heavy lifting are done in background queues.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let context = coreDataStack.mainContext | |
// We can use the main context here because we only read the `Media` instance, without changing it, and all | |
// the time consuming work is done in background queues. | |
let context = coreDataStack.mainContext |
/// - onCompletion: Completion handler passing the URL once available, or nil if unavailable. | ||
/// - onError: Error handler. | ||
/// - onCompletion: Completion handler passing the URL once available, or nil if unavailable. This closure is called on the `exportQueue`. | ||
/// - onError: Error handler. This closure is called on the `exportQueue`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Originally, these closures are called on the managedObjectContext
queue. Since we don't have a long living context object anymore, they are changed to use the exportQueue
.
remoteURL = WPImageURLHelper.imageURLWithSize(preferredSize, forImageURL: remoteAssetURL) | ||
} else { | ||
remoteURL = PhotonImageURLHelper.photonURL(with: preferredSize, forImageURL: remoteAssetURL) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The above changes are mainly for removing the onCompletion(nil)
calls above, which are now covered by the guard let imageURL = remoteURL
case below.
private let onSuccess: (UIImage) -> () | ||
private let onFailure: (Error) -> () | ||
|
||
init(url: URL, blog: Blog, onSuccess: @escaping (UIImage) -> (), onFailure: @escaping (Error) -> ()) { | ||
init(url: URL, blog: Blog, callbackQueue: DispatchQueue, onSuccess: @escaping (UIImage) -> (), onFailure: @escaping (Error) -> ()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Originally the onSuccess
closure is called on the main queue, and the onFailure
closure is called on a background thread that runs this operation. Adding this calbackQueue
to unify their calling queue. Also, it makes the enforcing callback queue code in MediaThumbnailService
nicer, without requiring additional async
calls there.
@@ -140,6 +145,7 @@ class EditorMediaUtility { | |||
let imageDownload = AuthenticatedImageDownload( | |||
url: requestURL, | |||
blog: post.blog, | |||
callbackQueue: .main, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be an improvement to the existing behaviour, since onFailure
wasn't called on the main thread, but I believe this function requires the error handling to be on the main thread.
@@ -121,8 +121,7 @@ class MediaLibraryPickerDataSourceTests: CoreDataTestCase { | |||
|
|||
let mediaService = MediaService(managedObjectContext: mainContext) | |||
let expect = self.expectation(description: "Media should be create with success") | |||
mediaService.createMedia(with: url as NSURL, blog: blog, post: post, progress: nil, thumbnailCallback: { (media, url) in | |||
}, completion: { (media, error) in | |||
mediaService.createMedia(with: url as NSURL, blog: blog, post: post, progress: nil, thumbnailCallback: nil, completion: { (media, error) in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just a small thing I noticed—no point passing an empty closure if nil
is an acceptable argument.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
📲 You can test the changes from this Pull Request in WordPress Alpha by scanning the QR code below to install the corresponding build.
|
📲 You can test the changes from this Pull Request in Jetpack Alpha by scanning the QR code below to install the corresponding build.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unlike other similar PR, this PR has changes that are not just simply swapping
NSManagedObjectContext
withCoreDataStack
. I'll add some PR comments for detailed reasons.
Thanks!
Mainly the uploading feature in the "Media" screen is impacted. Verifying uploading media still works should be sufficient.
Upload successful and the thumbnails appear alright.
let mediaService = MediaService(managedObjectContext: coreDataStack.mainContext) | ||
mediaService.getMediaWithID(mediaID, in: media.blog, success: { (loadedMedia) in | ||
onCompletion(loadedMedia, nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think of tracking what your wrote in the comment above in the code?
let mediaService = MediaService(managedObjectContext: coreDataStack.mainContext) | |
mediaService.getMediaWithID(mediaID, in: media.blog, success: { (loadedMedia) in | |
onCompletion(loadedMedia, nil) | |
// It's only safe to use the main context as the MediaService instance's context because a Media object is | |
// leaked out of MediaService's lifecycle (MediaService.managedObjectContext's to be exact. | |
let mediaService = MediaService(managedObjectContext: coreDataStack.mainContext) | |
mediaService.getMediaWithID(mediaID, in: media.blog, success: { (loadedMedia) in | |
onCompletion(loadedMedia, nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, SwiftLint might at some point complain about the redundant ()
around loadedMedia
. 🤷♂️
/// | ||
/// - Note: Images may be downloaded and resized if required, avoid requesting multiple explicit preferredSizes | ||
/// as several images could be downloaded, resized, and cached, if there are several variations in size. | ||
/// | ||
@objc func thumbnailURL(forMedia media: Media, preferredSize: CGSize, onCompletion: @escaping OnThumbnailURL, onError: OnError?) { | ||
managedObjectContext.perform { | ||
let context = coreDataStack.mainContext |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let context = coreDataStack.mainContext | |
// We can use the main context here because we only read the `Media` instance, without changing it, and all | |
// the time consuming work is done in background queues. | |
let context = coreDataStack.mainContext |
private func downloadThumbnail( | ||
forMedia media: Media, | ||
preferredSize: CGSize, | ||
callbackQueue: DispatchQueue, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
callbackQueue: DispatchQueue, | |
callbackQueue: DispatchQueue, |
@@ -121,8 +121,7 @@ class MediaLibraryPickerDataSourceTests: CoreDataTestCase { | |||
|
|||
let mediaService = MediaService(managedObjectContext: mainContext) | |||
let expect = self.expectation(description: "Media should be create with success") | |||
mediaService.createMedia(with: url as NSURL, blog: blog, post: post, progress: nil, thumbnailCallback: { (media, url) in | |||
}, completion: { (media, error) in | |||
mediaService.createMedia(with: url as NSURL, blog: blog, post: post, progress: nil, thumbnailCallback: nil, completion: { (media, error) in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Unlike other similar PR, this PR has changes that are not just simply swapping
NSManagedObjectContext
withCoreDataStack
. I'll add some PR comments for detailed reasons.Test instructions
Mainly the uploading feature in the "Media" screen is impacted. Verifying uploading media still works should be sufficient.
Regression Notes
Potential unintended areas of impact
None.
What I did to test those areas of impact (or what existing automated tests I relied on)
What are described in the "Test instructions" above.
What automated tests I added (or what prevented me from doing so)
None.
PR submission checklist:
RELEASE-NOTES.txt
if necessary.