{"id":3122,"date":"2015-01-10T01:28:46","date_gmt":"2015-01-10T07:28:46","guid":{"rendered":"http:\/\/benincosa.com\/?p=3122"},"modified":"2015-01-10T01:28:46","modified_gmt":"2015-01-10T07:28:46","slug":"ios-bounds-vs-frames","status":"publish","type":"post","link":"https:\/\/benincosa.com\/?p=3122","title":{"rendered":"iOS: bounds vs. frames"},"content":{"rendered":"<p>I got totally hosed this week trying to add a subview to a UITableViewCell. \u00a0The cool thing is that I learned a lot.<\/p>\n<p>I created a custom UITableViewCell that called FeedCommentTableViewCell class. \u00a0Below is the working code:<\/p>\n<pre class=\"lang:objc decode:true\">#import \"FeedCommentTableViewCell.h\"\r\n#import \"Settings.h\"\r\n\r\n@implementation FeedCommentTableViewCell\r\n\r\n\r\n- (void)layoutSubviews {\r\n    [super layoutSubviews];\r\n    CGRect labelFrame = CGRectMake(LEFT_PAD, 0, (self.contentView.bounds.size.width - 2 * LEFT_PAD), self.contentView.bounds.size.height);\r\n    self.commentLabel.frame = labelFrame;\r\n}\r\n\r\n\r\n- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {\r\n    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];\r\n    if (self) {\r\n        _commentLabel = [[STTweetLabel alloc] initWithFrame:CGRectZero];\r\n        _commentLabel.font = COMMENT_FONT;\r\n        _commentLabel.numberOfLines = 0;\r\n        _commentLabel.lineBreakMode = NSLineBreakByWordWrapping;\r\n        [self.contentView addSubview:self.commentLabel];\r\n    }\r\n    return self;\r\n}\r\n\r\n\r\n\r\n@end<\/pre>\n<p>A few lessons learned:<\/p>\n<p>1. \u00a0initWithStyle is called only when the cell is created and thus will be used multiple times. \u00a0So I set the frame to zero realizing that this cell will dynamically change in size based on a function I wrote in the UITableViewController subclass.<\/p>\n<p>2. \u00a0Based on experiments suggested by <a href=\"http:\/\/stackoverflow.com\/questions\/14640680\/when-exactly-does-layoutsubviews-get-called-for-custom-uitableviewcell\">this post<\/a>, I learned that tableview:CellForRowAtIndexPath will get called first and at the very last layoutSubviews will be called as the cell is displayed. \u00a0This is the place to set the size of the subviews based on the size of the cell.<\/p>\n<p>3. \u00a0I was setting my (commentLabel in the example above) subview&#8217;s frame based on the cell&#8217;s frame (self.frame). \u00a0This was a no-no.<\/p>\n<p>Expanding on number 3.<\/p>\n<p>Let&#8217;s say my layoutSubviews method wanted the commentLabel to be the same size as the cell itself. \u00a0I originally did something like the following:<\/p>\n<pre class=\"lang:objc decode:true\">- (void)layoutSubviews {\r\n    [super layoutSubviews];\r\n    self.commentLabel.frame = self.contentView.frame\r\n}\r\n<\/pre>\n<p>This would render the first cell perfect, but as I scrolled and scrolled back up I saw problems. \u00a0You see, self.contentView.frame is the coordinates of the cell in the parent view&#8217;s coordinate system. \u00a0We want to assign the frame of the commentLabel to be set to the coordinates based cell&#8217;s subview itself. \u00a0Simply moving this to something like:<\/p>\n<pre class=\"lang:objc decode:true \">- (void)layoutSubviews {\r\n    [super layoutSubviews];\r\n    self.commentLabel.frame = self.contentView.bounds;\r\n}\r\n<\/pre>\n<p>Adds this subview into the coordinate system of the contentView, which is what we want!<\/p>\n<p>Now I&#8217;m sure Autolayout and using Storyboards make this easier, but I&#8217;ve found that for more complex UITableViewCells, laying it out in code seems to be a lot easier to debug.<\/p>\n<p>Moving on to the rest of the project now that that bug is under my belt!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I got totally hosed this week trying to add a subview to a UITableViewCell. \u00a0The cool thing is that I learned a lot. I created a custom UITableViewCell that called FeedCommentTableViewCell class. \u00a0Below is the working code: #import &#8220;FeedCommentTableViewCell.h&#8221; #import &#8220;Settings.h&#8221; @implementation FeedCommentTableViewCell &#8211; (void)layoutSubviews { [super layoutSubviews]; CGRect labelFrame = CGRectMake(LEFT_PAD, 0, (self.contentView.bounds.size.width -&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[995,36],"tags":[642,643,641],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/posts\/3122"}],"collection":[{"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/benincosa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3122"}],"version-history":[{"count":1,"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/posts\/3122\/revisions"}],"predecessor-version":[{"id":3123,"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/posts\/3122\/revisions\/3123"}],"wp:attachment":[{"href":"https:\/\/benincosa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3122"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/benincosa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3122"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/benincosa.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3122"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}