1

I'm subclassing UIView to make a custom view by overriding drawRect:. I need to find a point that is equal to 10 percent of the View's width. Of course, that distance is trivial to calculate (self.bounds.size.width/10.0f). I would like to cache this value, that is, I want to store this value in an instance variable to avoid having to calculate it on every single drawRect:.

Inside what method would I store this value? I was thinking about just saving the variable's value while in initWithFrame:, but then the cached value would be out of sync with the view's width after any sort of resize.

Any thoughts on what the best place to cache the view's width is... and if it is even ok to do so?

aleph_null
  • 5,766
  • 2
  • 24
  • 39

2 Answers2

3

You can store the value in an ivar and (re)compute it in layoutSubviews.

However, this is an obvious case of premature optimization. You should focus on writing good code, and optimize when the need becomes apparent. In fact, this "optimization" could even have a negative impact on your app's performance: is it more expensive to divide two numbers or to look up the value of an ivar?

titaniumdecoy
  • 18,900
  • 17
  • 96
  • 133
3

that distance is trivial to calculate (self.bounds.size.width/10.0f)...

I would like to cache this value, that is, I want to store this value in an instance variable to avoid having to calculate it on every single drawRect:.

Everything here is trivial. There is no reason to cache it.

You have:

  • one objc message (which you would use to access a cached value)
  • then you access a field of a struct within a struct (practically free)
  • then you perform a floating point divide (still tiny relative to the operation)

Any thoughts on what the best place to cache the view's width is... and if it is even ok to do so?

The best place is right here:

- (void)drawRect:(CGRect)rect {
  // ...
  const CGFloat tenthWidth = self.bounds.size.width * 0.10f;
  // ...
}

also note the use of multiplication by the reciprocal ;)

Community
  • 1
  • 1
justin
  • 104,054
  • 14
  • 179
  • 226
  • thanks, that makes sense. Would it ever make sense to cache values that are dependent on the view's bounds, say if the computation involved something more complex than a product? – aleph_null Oct 20 '11 at 00:09
  • 1
    @aleph_null: Once again, you are speculating about possible optimizations without data. If and when a part of your application exhibits performance issues, profile it to figure out why, and optimize _then_. Otherwise you're just wasting time--and writing code that's more difficult to debug and maintain for no good reason. – titaniumdecoy Oct 20 '11 at 02:04
  • 1
    @aleph_null The safe place to calculate and store the result is within `drawRect:` (specifically, that variable would be local to `drawRect:` in the *vast* majority of cases). The view/frame should not change externally while you are in `drawRect:`. Now, if you want to be pedantic, there are a few scenarios where you would want to track bounds changes; a prerendered bitmap or image comes to mind. One would use this when drawing is very very complex, and when the bitmap does not change often. *However*, that case should typically just invalidate the backing image when bounds change. (cont) – justin Oct 20 '11 at 04:45
  • (cont) When asked to draw, the backing image would be recalculated if invalidated. In that case and a few others, yes it would in fact make sense, but the complexity of your problem versus the bitmap which is very very complex to create are at opposite ends of the spectrum. *echo titanium decoy's response to your question*. – justin Oct 20 '11 at 04:46
  • @Justin: The correct place to calculate and store the result (assuming it was a good idea; as we've established, it isn't in this case) is in `layoutSubviews`, not `drawRect:` as stated in my answer. Also, the variable should definitely not be "local to [the function]" (by which I assume you mean static): it should be an ivar so that it is not shared between instances of the class. – titaniumdecoy Oct 20 '11 at 16:41
  • @titaniumdecoy a) only some of the time b) no -- do not assume `static`. `tenthWidth` (above) is an example of a (constant) variable local to `drawRect:`. – justin Oct 20 '11 at 19:04
  • @Justin: a) Given the problem stated by the aleph_null, `layoutSubviews` would be the correct place for the computation in question, and not "only some of the time". b) In that case you're not "storing" anything, you're just recomputing the value every time `drawRect:` is invoked. – titaniumdecoy Oct 20 '11 at 19:50
  • @titaniumdecoy a) b) Your definition of 'store' is wrong. 'Store' is **not** a synonym for 'cache externally'. – justin Oct 20 '11 at 20:27
  • @Justin: Given the context of this discussion, when you say "store" it is reasonable to assume that you mean "cache" in some way (externally or not). Anyway, this discussion isn't going anywhere so let's forget it. – titaniumdecoy Oct 20 '11 at 20:53
  • @titanimdecoy I have to wonder if you were the anonymous downvoter to my answer, it seems possible given the recent activity of this question... anyhow... no, your assumption is wrong *again*. **Example:** The first time I wrote 'store' I specified that it "would be to a variable local to `drawRect:` in the vast majority of cases" *in the same sentence*. In fact, every use of 'store' in the question, the answers, and the comments *also* specifies a destination - 'store' is not implicitly external. There is one exception: your comment. Not surprising since your definition/assumption is wrong. – justin Oct 20 '11 at 21:28
  • @Justin: You're right. I did downvote your answer, which was poor judgment. I would however be happy to reverse my downvote if you give me the chance by editing your answer. – titaniumdecoy Oct 20 '11 at 22:02
  • @titaniumdecoy Although I've edited the post, it's not the rep that is important, It's the honesty, and I thank you for that. – justin Oct 20 '11 at 22:09
  • @Justin: No problem. Sorry for being so pedantic. – titaniumdecoy Oct 20 '11 at 22:33
  • @titaniumdecoy it's cool. sorry if my word choice was poor or confusing. – justin Oct 20 '11 at 23:36
  • I agree, caching a value to save a single produce is kind of pointless... but, I'm sure there are those rare situation in which caching values could be a good idea, especially if many complex calculations are involved in calculating the values. Thanks to both of you. – aleph_null Oct 22 '11 at 18:37