-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Make objects conform to NSLocking #851
Conversation
…t users/subclasses can access their locks
Source/ASNetworkImageNode.mm
Outdated
__weak id<ASNetworkImageNodeDelegate> _delegate; | ||
|
||
NSURL *_URL; | ||
UIImage *_defaultImage; | ||
|
||
NSUUID *_cacheUUID; | ||
std::atomic_uint _cacheToken; |
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.
We may should have this change in a follow up diff. Not really 100% related to adopting NSLocking.
@@ -1,40 +0,0 @@ | |||
// | |||
// ASDisplayNode+FrameworkSubclasses.h |
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.
Nice that we can get rid of that
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.
[EDIT] Since investments in our locking infrastructure are relatively rare, it's exciting to see such a thoughtfully considered API design and underlying implementation. Great changes across the board!
Feedback is minor, mostly interested in developing a style recommendation for whether [self lock] vs the AS* methods will be most common and try to standardize on that within the framework. This shouldn't block landing.
It seems like a good idea to adopt NSLocking to encourage third party developers with the need for custom locking to use the -lock/unlock methods.
Source/ASImageNode.mm
Outdated
|
||
ASImageNodeDrawParameters *drawParameters = [[ASImageNodeDrawParameters alloc] init]; | ||
drawParameters->_image = [self _locked_Image]; | ||
drawParameters->_bounds = [self threadSafeBounds]; | ||
drawParameters->_bounds = self.bounds; |
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.
Is this particular change necessary, and also safe? IIRC it was important to use threadSafeBounds here.
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.
Oh I didn't know. When I removed the FrameworkSubclasses import, the import for this field was lost and I figured it was OK to use bounds since this method is (allegedly) called on main. I put it back since the change is outside the purview of this diff 👍
__weak id<ASNetworkImageNodeDelegate> delegate = _delegate; | ||
BOOL delegateDidStartFetchingData = _delegateFlags.delegateDidStartFetchingData; | ||
BOOL isImageLoaded = _imageLoaded; | ||
NSURL *URL = _URL; | ||
id currentDownloadIdentifier = _downloadIdentifier; | ||
__instanceLock__.unlock(); | ||
[self unlock]; |
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 difference in style between these statements and the macros feels a bit less prominent / conspicuous than before, where all locks involved instanceLock.
I wonder if we should use a macro for even the simple lock / unlock message send, just to make locking operations consistent? Even if we did that, lock / unlock would still be available, especially for third party code.
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.
It's true – I'm iffy on this. I totally see your point that there's a mismatch in look and feel, but I don't like when there's two ways to do the same thing, and I like the referential transparency.
I also kind of like the mismatch, since it "discourages" use of these methods by making them stick out.
Let's sleep on this. There will be more locking diffs in the future and we can add the macros easily at any time.
Source/ASVideoNode.mm
Outdated
__instanceLock__.lock(); | ||
|
||
ASUnlockScope(self); | ||
[self addSubnode:_playerNode]; |
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.
I'm not sure if it is important to re-lock before the setNeedsLayout, but the locking scope did change here (may want to add a { } scope around the addSubnode)
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.
Good catch, either way it's outside the scope of this diff 👍
@@ -232,6 +232,26 @@ | |||
((c *) ([__val class] == [c class] ? __val : nil));\ | |||
}) | |||
|
|||
// Compare two primitives, assign if different. Returns whether the assignment happened. | |||
#define ASCompareAssign(lvalue, newValue) ({ \ |
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.
Shouldn't there be a variant that does use ASObjectIsEqual, but doesn't do a copy (just a regular assignment which may involve a retain?)
Is there any way to enforce that ASCompareAssign is not used for objects accidentally?
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.
Good point, I added that variant as ASCompareAssignObject
.
I think there's value in using plain ASCompareAssign for objects, in the case where we want to skip the isEqual:
(say, in setDelegate:
or similar), so I'd rather keep that option open.
Generated by 🚫 Danger |
* Make display node, layout spec, and style conform to NSLocking so that users/subclasses can access their locks * Update the changelog * Align slashes * Put it back, when we're in ASDisplayNode * Go a little further * Put back the changes I didn't mean to commit * Kick the CI * Fix yoga build * Put back non-locking change * Address comments from Scott
NSLocking
. They use the same__instanceLock__
as before, but they can be publicly locked and unlocked.ASThread.h
(public) has useful C++-esque locking macros.ASLockScope(id<NSLocking> l)
retains and adds the lock to the current scope.ASLockScopeSelf
locks self for the current scope. Skips retain (self is safe.)ASLocked(id<NSLocking> l, expr)
Evaluates to theexpr
while holding the lock.ASLockedSelf(expr)
Evaluates to theexpr
while using self as the lock (skip retain).ASCompareAssign(lvalue, newValue)
compares the two values, updating the lvalue if different, returns BOOL.ASLockedSelfCompareAssign(lvalue)
Same as above but holds self as lock.