{"id":1210,"date":"2015-08-10T16:39:14","date_gmt":"2015-08-10T16:39:14","guid":{"rendered":"https:\/\/zogspat.tk\/blog\/?p=1210"},"modified":"2015-08-10T16:39:14","modified_gmt":"2015-08-10T16:39:14","slug":"building-an-electronic-programme-guide-part-3","status":"publish","type":"post","link":"https:\/\/the-plot.com\/blog\/?p=1210","title":{"rendered":"Building an Electronic Programme Guide [part 3]"},"content":{"rendered":"<p>This is my third and final write-up on the development of an electronic programme guide app. As of part 2, the main scrolling view with the programme details, scaled to length, are displayed.<\/p>\n<p>Next up I wanted to have the ability to display programme details. This seemed like it was going to be pretty straightforward: when building the per-programme view, I included a button, which is transparent, and has the same dimensions as the view itself. The first problem is associating the programme details with the button itself. There is plenty of discussion on StackOverflow about how to do this in the least offensive way. I went with a category and then object association. This allowed me to set the GUID as a property for the button.<\/p>\n<p>I rebuilt the app, hit the button and\u2026 entered into a fortnight of debugging an EXC_BAD_ACCESS error. I knew what the problem was: the ARC memory management was dereferencing the button object once it was set. I tried lots of different options, such as adding the buttons to an array, set with various properties, and passing the array back to the main view controller. Nothing worked until I did more reading around the property attributes, and ended up redefining the Interface Builder defaults for the scrolling contentView to:<\/p>\n<pre>@property (nonatomic, strong) IBOutlet UIView *contentView;<\/pre>\n<p>That \u2018strong\u2019 means that everything in the view is held in memory. It has to be said that the app is very heavy on memory &#8211; as a direct consequence of that view object retention. It routinely occupies 63Mb in my testing.<\/p>\n<p>Next up is the popup that is rendered. So finding the programme itself is pretty easy, using an NSPredicate based on the GUID. What proved a bit harder to deal with is if the main view [the \u2018contentView\u2019 for the scrollView] is zoomed. As you have to add the popup view to the zoomed parent, the former is going to inherit the zoom setting. I couldn\u2019t think of an elegant way around this so I worked around it in stages. First off, the popup sits on a blurred view of the current background:<\/p>\n<pre>\/\/ This is quite neat: make a CGRect of the currently visible part of the scrollview:\r\nCGRect visibleRect = [scrollView convertRect:scrollView.bounds toView:contentView];\r\nvisualEffectView = [[UIVisualEffectView alloc] initWithFrame:visibleRect];\r\nvisualEffectView.effect = blurEffect;\r\nvisualEffectView.frame = contentView.bounds;\r\n[contentView addSubview:visualEffectView];<\/pre>\n<p>Next, I register the scrollView offset in a property:<\/p>\n<pre>scrollOffSet = scrollView.contentOffset;<\/pre>\n<p>\u2026set the zoomScale to 1, and disable the ability to zoom:<\/p>\n<pre>[scrollView setZoomScale:1.0];\r\nscrollView.scrollEnabled = NO;\r\nscrollView.maximumZoomScale = 1.0;\r\nscrollView.minimumZoomScale = 1.0;<\/pre>\n<p>Placing the programme details subview is then relative to the currently visible rectangle:<\/p>\n<pre>float xForLittleView = visibleRect.origin.x + 30 ;\r\nfloat yForLittleView = visibleRect.origin.y + 100;\r\n\r\nCGRect progViewRect = CGRectMake(xForLittleView, yForLittleView, 350, 500);<\/pre>\n<p>I then have to undo the various view settings when the button to dismiss the view is touched:<\/p>\n<pre>[visualEffectView removeFromSuperview];\r\n[littleView removeFromSuperview];\r\nscrollView.scrollEnabled = YES;\r\nscrollView.maximumZoomScale = 2.0;\r\nscrollView.minimumZoomScale = 0.8;\r\n[scrollView setZoomScale:zoomScale];\r\n[scrollView setContentOffset:scrollOffSet];<\/pre>\n<p>It\u2019s all a bit clunky, but it works. I imagine that this sort of interface plumbing actually happens quite a lot behind the scenes. That said, I may have missed a trick to do it in an easier way.<\/p>\n<p>I\u2019ll call out two more details that I wrestled with. The first is a search facility on the programme title. I wanted the NSPredicate to support as many search terms as the user entered. My initial idea was to split the UITextField input on spaces, and then loop through the resulting array, appending to a stringWithFormat, where all but the first element would be in the form:<\/p>\n<pre>AND (title CONTAINS[c][\/c] %@)<\/pre>\n<p>Having experimented with this, it appears that predicateWithFormat has to have the actual string passed to it, as opposed to a variable containing the string. Which I have to say strikes me as a little odd. The functional upshot of this is that I couldn\u2019t support a variable number of search terms. I support up to three, and construct a separate predicateWithFormat for each possibility.<\/p>\n<p>One final problem that I couldn\u2019t find a fix for was implementing a UITableView\u2019s delegates in a class that I pass the view into as a parameter. I couldn\u2019t find a way of getting the cellForRowAtIndexPath delegate method to be called. The conclusion I came to with this was that it was setting the delegate to self, when \u2018self\u2019 was the custom object, rather than the view. It was largely a cosmetic thing [I\u2019ve noticed that for complicated apps, I have a tendency to pile way to much code into the main viewController] so it was easily solved.<\/p>\n<p>Here\u2019s what may be the final version of the app looks like, showing a search result in the popup view, and the to\/from dates for the EPG coverage:<\/p>\n<div id=\"attachment_1211\" style=\"width: 1252px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/the-plot.com\/blog\/wp-content\/uploads\/2015\/08\/IMG_3380.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-1211\" class=\"size-full wp-image-1211\" alt=\"Search Results\" src=\"https:\/\/the-plot.com\/blog\/wp-content\/uploads\/2015\/08\/IMG_3380.png\" width=\"1242\" height=\"2208\" srcset=\"https:\/\/the-plot.com\/blog\/wp-content\/uploads\/2015\/08\/IMG_3380.png 1242w, https:\/\/the-plot.com\/blog\/wp-content\/uploads\/2015\/08\/IMG_3380-168x300.png 168w, https:\/\/the-plot.com\/blog\/wp-content\/uploads\/2015\/08\/IMG_3380-576x1024.png 576w\" sizes=\"auto, (max-width: 1242px) 100vw, 1242px\" \/><\/a><p id=\"caption-attachment-1211\" class=\"wp-caption-text\">Search Results<\/p><\/div>\n<p>The other buttons that I haven\u2019t talked about explicitly are an ability to switch between days, and initiate a download of EPG data &#8211; but which are pretty straightforward. What\u2019s still either ugly or hasn\u2019t been fully implemented is the download progress indicator, and also the what\u2019s-on-now quick look on the Apple Watch, as I want to have a mess around with something completely unrelated to this app: the motion detection capability.<\/p>\n<p>I did add a quick fix to &#8216;justify&#8217; the right hand side of the &#8216;table&#8217; of programmes. Formerly they were falling off the contentView. I simply check if the rightmost width of the cell is going to be greater than the width of the contentView. If so, I set it to be the same as the width.<\/p>\n<p>So that\u2019s it. I have a pretty serviceable EPG app, which I use myself over the ad-funded variant I had before, which I guess is a fair indicator of utility. Main lesson learned: not knowing what those property attributes meant tripped me up really badly!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is my third and final write-up on the development of an electronic programme guide app. As of part 2, the main scrolling view with the programme details, scaled to length, are displayed. Next up I wanted to have the &hellip; <a href=\"https:\/\/the-plot.com\/blog\/?p=1210\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,5],"tags":[],"class_list":["post-1210","post","type-post","status-publish","format-standard","hentry","category-ios-development","category-tech"],"_links":{"self":[{"href":"https:\/\/the-plot.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1210","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/the-plot.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/the-plot.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/the-plot.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/the-plot.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1210"}],"version-history":[{"count":1,"href":"https:\/\/the-plot.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1210\/revisions"}],"predecessor-version":[{"id":1212,"href":"https:\/\/the-plot.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1210\/revisions\/1212"}],"wp:attachment":[{"href":"https:\/\/the-plot.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1210"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/the-plot.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1210"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/the-plot.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1210"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}