Swift resources

There are a tons of very useful resources out there for Swift and I have barely begun to scratch the surface. But below are some the resources that I have found invaluable in my few months of Swift coding.

  • http://objc.io is a website with 24 online magazine issues dealing with different iOS concepts in detail. Inspite of most of the articles written in Objective C, most of the concepts explained are iOS related which are relevant irrespective of the language used ( Swift or Objective C)
  • http://www.raywenderlich.com/ – Has very detailed text and video tutorials
  • https://www.udemy.com/the-complete-ios-9-developer-course/learn/#/ – Udemy course by Rob Percival. I am 30% there and I have found this course to start from Swift basics to important advanced features
  • Stack overflow: Most of the questions that have arisen for me have been asked here. I did have trouble in coming up with optimal search query that will get me to the answer.

I have used other resources while searching, but these have been the locations that I have referred to the most often.

Swift resources

How to create UITableViewCell with different UITableViewCellStyle?

Before I describe the issue I faced and how I solved it, here are a few resources regarding UITableViewCell style.

  • UITableView is the built-in control of iOS to create tables with a comprehensive set of delegate methods giving developers the option to customize.
  • UITableViewCell represents each row in a UITableView in iOS.
  • UITableViewCellStyle represents the different styles a row can be initialized in. The default value for this is , surprise, .Default. More details on what each of them indicate is here

There are 2 ways in which you can specify the type of UITableViewCell that you want to use for your UITableView:

  1. If you have only one type of cell in uitableview then you can use the following code in the uitableviewdelegate:cellForRowAtIndexPath

    With this method it is pretty straightforward to change the style of the uitableview cell to the desired value.
  2. The second, and more commonly used method, involves 2 steps:
    1. First, register the cell types that you are going to use in your uitableview in the viewDidLoad() method of you uitableviewcontroller
    2. Second, in uitableviewdelegate:cellForRowAtIndexPath, add the below method to use the registered cell class

      In this second method there is no straightforward way to change the style of the UITableViewCell as it was in previous method.

So when I was faced with this issue, I figured, this seems to be a pretty simple thing, Swift should have provided me a way with changing the cell style. I searched far and wide in stackoverflow.com and the only option is to create a new custom cell derived from UITableViewCell and override the constructor to change style if you are following the second method of initialization

So below is the sample custom cell to create a uitableview cell with .SubTitle style

Hopefully this will save you some time in trying to figure out if a simpler way exists

How to create UITableViewCell with different UITableViewCellStyle?

iOS autolayout tutorials

I solved some autolayout issues without much priori knowledge. Though it took long, it peaked my interest in reading more about autolayout. Below are few links ( mostly google results) about autolayout that I am hoping to read more thoroughly and write some blog posts on

iOS apple autolayout guide

Ray Wenderlich beginning autolayout tutorial part 1

Ray Wenderlich beginning autolayout tutorial part 2 

Mobile OOP autolayout advanced tutorial

Debugging autolayout issues

iOS autolayout tutorials

WKWebView target=_blank quirks

My previous post deals with the different javascript-related WKWebView quirks . The first issue I mention is

WKWebView does not open any <a> links that have target=”_blank

In summary from the previous post, This issue can be resolved by implementing WKUIDelegate method as below to intercept links that request for a new webView ( new tab/window) and force them to render in the current instance of webView.

During my testing of our company’s app with the above fix, I found that clicking links inside any google plus site result in empty page rendering in WKWebView.

To summarize:

  • Clicking on SOME <a> links with attribute target=”_blank” result in empty page rendering

Upon debugging, I figured out that the WKUIDelegate method is indeed getting called as expected, but the navigationAction.request is empty ( Optional(“”))

After posting a stack over flow question here and trying out remote safari debugging as described here, I still could not figure out why the WKWebView delegate has an empty url passed in as request.

So, I used the fallback option of executing javascript code in the WKNavigationDelegate method of didFinishNavigation that gets called once the webPage is loaded

The javascript code does the following:

  • Get the list of all the links in the web Page
  • Loop through the list of links and do the following
    • If the link has a target attribute set AND the attribute value is “_blank” , we update the attribute value to be “_self”

_self indicates that the link referenced in <a> tag needs to be opened in the current instance of webView instead of new tab or new window ( target = “_blank” indicates that the browser should try and open the link in new window/tab)

Refer here for details on different values of  target attribute.

With this code, the links inside google plus posts open in the same WKWebView instance  ( Eg: tom cruise google plus posts and click on any link)

WKWebView continues to give me these quirks/headaches, though in all fairness this issue exists in UIWebView as well. UIWebView also does not have the fancy delegate method as WKWebView for intercepting calls to create new webViews, so if you are using UIWebView, javascript code is your only option

WKWebView target=_blank quirks

WKWebView javascript quirks

WKWebView is the more performant webview control introduced by Apple for iOS and OSX apps. You can read more about this in my previous post.  But as the post mentions there are many features missing that are present in the UIWebView control. One such quirk is related to how WKWebView handles javascript actions that result in an alert, prompt (or) request to open a new url in a new window(tab). If we dont correctly handle, all of these clicks will result in no-op in WKWebView.

  • WKWebView does not open any <a> links that have target=”_blank”. ( For eg: From inside a WKWebview, if you click on the trailers in http://www.tomcruise.com website , nothing happens).  In desktop browser, if target is “_blank”, a new tab is opened. In the in-app browser, we usually want the page to load on top of the current one. In order to achieve that in WKWebView, the following steps need to be followed.
    • Make your view controller that handles the webView callbacks to implement WKUIDelegate
    • In the view controller add the following code. This code verifies if the navigationAction’s target frame is nil(happens when target=”_blank”) and calls loadRequest on the navigationAction.request using current webview. The method ends with returning nil as we did not create a webView and used the existing one instead

  • WKWebView does not display the following Javascript prompts that are requested by web page.
    • Javascript prompt that shows a message that user can dismiss by a button pressWKWebView does not render any of the following prompts that are initiated by javascript code inside the WKWebView
    • Javascript prompt with OK and Cancel buttons, asking for user to make a choice of further action
    • Javascript prompt that asks for text input from user with an OK and Cancel buttons

To ensure all these three different javascript prompts show up, ensure that you have implemented the following three WKUIDelegate methods. The delegate methods give us access to the completion handler and which type of Javascript prompt to create. We need to create an iOS alert in the delegate method and render it modally for users to interact with.

I dont know why Apple’s Webkit could not have included a default implementation for these delegate methods with the creation and displaying alert controller

WKWebView javascript quirks

How to take UIWebView screenshot in Swift on iOS?

One of the more frequent questions on stack overflow is how to take a screenshot of a webView.

While working on our company’s app, I initially had to implement screenshot on UIWebView and recently had to port the code to use WKWebView and implement the same screenshot code. I initially started off to share code for wkwebview and uiwebview. But the post of UIWebView got so long that I decided to restrict this post to UIWebView full screenshot

For full screenshot in UIWebView

  1. Save the current frame of the uiwebview object
  2. Update frame to be same as uiwebView.scrollview height ( This step is necessary as you are taking a screenshot of the entire web Page content, including below the fold as well)
  3. Create a CGRect with ( height = uiwebview.scrollview.height , width = screen.width)

The next step is to generate a UIImage which contains the “snapshot” of the current state of the UIWebView. For this we need to draw the UIWebView’s snapshot into a graphics context , capture the screenshot and generate the UIImage object. For more details on graphics context, refer here

4. Call UIGraphicsBeginImageContext to create a new graphics context and to make it the default graphics context

5. Call function to render the webView.layer into the current graphics context

6. Call UIGraphicsGetImageFromCurrentContext to generate a UIImage object from the current context

7. Call UIGraphicsEndImageContext to uninitialize the  graphics context created in step 4

Below is the code to generate the uiwebview screenshot assuming you have the uiwebview object

Potential code modifications you might need to consider:

  1. renderInContext consumes a lot of memory ( potentially 150MB which can result in memory termination of the app) for rendering the entire webPage into the current graphics context. Refer to this link for potential work around. ( I personally find it hacky)
  2. You can play with the parameters to UIGraphicsBeginImageContextWithOptions depending on your requirement. Refer to this and this for more ideas
  3. If you want to take the screenshot of only visible portion of the UIWebView, the following modifications need to be made
    1. Ignore all changes to scrollView offset
    2. The webView frame is set to be of device’s height and width
    3. The size of the context also needs to be set to be same as the device’s screen size
  4. You can generate a JPG or PNG data from the UIImage  object using UIImageJPEGRepresentation and UIImagePNGRepresentation
  5. If your UIWebView can render any possible external website, test for different sites (use different technology) that render different content ( excel, pdf, ppt).
  6. Remember WKWebView is much more performant, albeit few features missing,  webView control . Make sure you analyze your requirements and see if you could take advantage of this control

Links

List of all the links referenced in this blog post

iOS Drawing Concepts

renderInContext consumes a lot of memory and eventually crashes

UIImageJPEGRepresentation

UIImagePNGRepresentation

UIGraphicsBeginImageContextWithOptions

WKWebView ( part of WebKit framework)

Captured screenshot is not of retina quality 

How to take UIWebView screenshot in Swift on iOS?

WKWebView – slice of Safari in your app

WKWebView was introduced in WWDC 2014 as an open source alternative to UIWebView for iOS and Mac apps.

WKWebView boasts of many advantages over UIWebView, some of which are included below:

  • WKWebView has very few/no memory leaks as opposed to UIWebView
  • WKWebView boasts Nitro javascript engine, same as used by Safari
  • Each WKWebView tab is opened in a new Process different than the app providing new and different resource pool that is separate from the app.
  • Some studies have shown that for some resource-intensive websites, the CPU usage is much lower
  • WKWebView provides key value observing (KVO) capability for web-related attributes ( change in title of webpage, estimated progress of loading of web page etc). For a detailed list of the WKWebView’s support KVO properties, refer here

Your next question should be, “What is the catch?”.

WKWebView was released without all the features of UIWebView.  Many of these are slowly being addressed over the last year. As of iOS 8.4 ( current greatest released iOS version), some of the cons are:

  • Requests made from WKWebView cannot be customized using NSURLProtocol
  • WKWebView does not have a good story defined around cookie-management ( should be fixed in iOS 9 to be released in October)
  • WKWebView cannot render content from local file unless it resides in /tmp folder.
  • As every WKWebView tab is opened in a new process, it is hard to visualize the memory consumption by WKWebView from Xcode

In my coming posts, I will focus on the gotchas related to WKWebView that I figured out while coding it up.

WKWebView – slice of Safari in your app