Reputation: 22252
I have a UIView
subclass that manipulates a number of layers. Because the view's layer's sublayers
retains the layers strongly, my thought was to make my own references to them weak:
@interface AnchorCell : UICollectionReusableView
@property (weak, nonatomic) CAShapeLayer *link;
@property (weak, nonatomic) CATextLayer *offset;
@end
I can do a certain amount of setup at init time. But I end up writing code like this:
- (void) initLink {
CAShapeLayer *shape = _link = [CAShapeLayer layer]; // have to put it in local variable to make it last long enough to get to the sublayer
_link.strokeColor = [[UIColor orangeColor] colorWithAlphaComponent: 1].CGColor;
_link.fillColor = nil;
_link.lineWidth = 3;
_link.masksToBounds = NO;
....
[self.layer addSublayer: _link];
}
I'm curious if there's a better idiomatic way to do this. What I like about the above, is that it highlights as much as possible, that I'm setting up the link
variable, instead of some local shape
variable, which I then set to link
at the end. What I don't like about it is that you have to add a local variable for no apparent reason that Xcode warns about.
I could move the addSublayer:
to the top of the method:
- (void) initLink {
CAShapeLayer *shape = [CAShapeLayer layer];
[self.layer addSublayer: shape];
_link = shape;
_link.strokeColor = [[UIColor orangeColor] colorWithAlphaComponent: 1].CGColor;
_link.fillColor = nil;
_link.lineWidth = 3;
_link.masksToBounds = NO;
}
But this hides things (to me) as well. It doesn't make it clear that link
has been added as a sublayer. Also, sometimes, there are patterns where you have to do a certain amount of setup to the object before you register it elsewhere.
Is there a more elegant way of doing this? Or at least a more idiomatic way given the restrictions of ARC managed ObjectiveC?
Upvotes: 3
Views: 411
Reputation: 437532
I don't think you should be making properties strong
just to avoid the use of a local variable (and if the property is weak
, you need the local variable).
I think the memory semantics (e.g. weak
vs strong
vs copy
) should reflect the functional object ownership graph, not sleight of hand just to avoid the use of a local variable. I would leave the property as weak
, and then do the obvious:
CAShapeLayer *shape = [CAShapeLayer layer]; // have to put it in local variable to make it last long enough to get to the sublayer
shape.strokeColor = [[UIColor orangeColor] colorWithAlphaComponent: 1].CGColor;
shape.fillColor = nil;
shape.lineWidth = 3;
shape.masksToBounds = NO;
....
[self.layer addSublayer: shape];
self.link = shape;
Personally, I don't I think the line that assigned both shape
and _link
in a single line of code improved its readability, so I prefer to separate those, but do whatever you want.
Furthermore, I generally advise the use of the setter, because I never know if I might have a custom setter or change the memory semantics at some future date (and the code here shouldn't be concerned about that). More than once I've had to refactor code that used the ivar directly because some implementation detail changed at a later date, but I have yet to regret using the accessor methods.
Upvotes: 4
Reputation: 1230
You might want to try code block evaluation, as described in this blog post.
Like:
_link = ({
CAShapeLayer *shape = [CAShapeLayer layer];
shape.strokeColor = [[UIColor orangeColor] colorWithAlphaComponent: 1].CGColor;
shape.fillColor = nil;
shape.lineWidth = 3;
shape.masksToBounds = NO;
[self.layer addSublayer: shape];
shape;
)};
Upvotes: 1
Reputation: 364
I don't think you need the temporary variable shape at all - simply do:
_link = [CAShapeLayer layer];
or
self.link = [CAShapeLayer layer];
Mind you, if you never need _link again once it becomes a sublayer then you can do it all with the local variable and skip the @property.
Hope this helps.
Upvotes: 0