Showing posts with label tutorial. Show all posts
Showing posts with label tutorial. Show all posts

Sunday, October 28, 2018

How to get old WWDC videos

It appears that old WWDC videos are removed from the official list. This post tells how to get them.
So, if you visit the developers's site from the above link you will see that currently available year range is only 2015–2018:
Even the search yields no results:
I had such a problem trying to find 8 year old video (WWDC 2010, Core Animation in Practice). Thanks to reddit community help, several solutions were found:
  1. WWDC videos prior to 2012 can be found in Developer Video Archive.
  2. From 2012 to 2015 they can be accessed by the link: https://developer.apple.com/videos/wwdc2012/. Just change the year in the end.
  3. The keynotes can be found in Podcasts.
Thats all!

Monday, June 4, 2018

How to convert HTML to NSAttributedString?

Well, simply don't. Use WKWebView instead.
This will allow you to insert pictures, reuse CSS-styles, execute scripts etc.

Wait, why not to use NSAttributedString?

While Apple provides several methods to initialize an instance of NSAttributedString from an HTML data, like: init(data:options:documentAttributes:), they are all extremely slow, about 1000 times slower than WKWebView which is as fast as Safari itself. Additionally, NSAttributedString supports a limited set of HTML attributes.

You may find many third-party solutions on GitHub (DTCoreText and many others). They can be faster, then the built-in converter, but still slower comparing to WebKit. I tried some, and they all were buggy and most are poorly supported after iOS7 release brought those "initWithHTML" methods.

The only advantage of NSAttributedString is the ability to put it in UI elements like UILabel or UIButton.

WKWebView example

Here follows super-advanced example demonstrating widest possible abilities of displaying rich and interactive text with HTML, CSS, and JavaScript. To make things convenient and reusable the HTML document is split into parts:

Tutorial_main.html

The main HTML that contains necessary elements that supposed to be involved in every page of the tutorial. Including:
  • A <head> block containing:
    • A raw CSS <style> section, containing easy-configurable constants.
    • An external CSS "stylesheet".
    • The extremely important "viewport" <meta> tag, required to scale content of a WKWebView correctly.
    • A <script> tag that provides Tutorial.js script. Not important enough to be listed here.
  • A customisable <body> section.
<html> <head> <style type="text/css"> :root { --softTextColor: %@; --darkTextColor: %@; --actionColor: %@; --backgroundColor: %@; --bodyFontSize: %@; --titleFontSize: %@; } </style> <link rel="stylesheet" type="text/css" href="Tutorial.css" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <script src="Tutorial.js"></script> </head> <body> %@ </body> </html> The %@ format specifiers will be replaced later with strings. Tutorial.css and Tutorial.js are contained in the Main Bundle root folder, so you don't need to specify baseURL to the WKWebView. Yes, you can refer local files, even use anchor links.

Tutorial.css

body { color: var(--softTextColor); font-family: "-apple-system"; font-size: var(--bodyFontSize); margin-top: 0px; text-align: left; -webkit-user-select: none; -webkit-touch-callout: none; background-color: var(--backgroundColor); } h1 { text-align: center; font-size: var(--titleFontSize); font-weight: 300; color: var(--darkTextColor); margin-top: 0.51em; margin-bottom: 0; margin-left: 0; margin-right: 0; } a { color: var(--actionColor); text-decoration: none; } It's handy to keep CSS in a separate file. You can see some constants which already were listed before.

step2_body.html

<h1>–°onnection</h1> <p>Connect your device to your computer using the USB cable.</p> <div class="spoiler"> <p>You can sync the device with iTunes using Wi-Fi. In this case you will need the USB cable only once: to activate wireless syncing. <a href="https://support.apple.com/en-us/HT203075">Read more.</a></p> </div> <div class="centered"> <a class="showMoreButton" href="showmore://"> <img src="show_more.svg" width=20 height=15 />show more </a> <a class="showLessButton" href="showless://"> <img src="show_less.svg" width=20 height=15 />show less </a> </div> The body of the second step. Look at two buttons, there is something interesting about them. First, they use .svg images, because WKWebView supports vector graphics. (Images are also placed in the root directory of the Main bundle). Also, buttons use custom-scheme anchors, e.g.: href="showmore://". These anchors allows to intercept button clicks on the Swift-side using the webView(,decidePolicyFor:,decisionHandler:) method of WKNavigationDelegate.

Assemble

Time to put all the things together. func assembleHTMLString(bodyFileName: String) -> String? { // All resources are contained in the Main Bundle let bundle = Bundle.main guard let mainHTMLURL = bundle.url(forResource: "Tutorial_main", withExtension: "html") else { print("No main HTML!") return nil } // The contents of Tutorial_main is not just a String, it's a format (see below) guard let mainHTMLFormat = try? String(contentsOf: mainHTMLURL, encoding: .utf8) else { print("Failed to parse \(mainHTMLURL.lastPathComponent)!") return nil } guard let bodyURL = bundle.url(forResource: bodyFileName, withExtension: "html") else { print("No body with name \(bodyFileName)!") return nil } guard let htmlBody = try? String(contentsOf: bodyURL, encoding: .utf8) else { debugLog("Failed to parse \(bodyFileName)!") return nil } // Prepare some necessary arguments... let arguments = [ // Following values will be used as CSS constants UIColor.lightGray.hexString, // softTextColor UIColor.gray.hexString, // darkTextColor UIColor.green.hexString, // actionColor UIColor.white.hexString, // backgroundColor "15px", // bodyFontSize "22px", // titleFontSize htmlBody // the body, yes ] // And here we ASSEMBLE! Finally. let assembledHTMLString = withVaList(arguments) { // The `arguments` substitute %@ in the `format`, one by one. (NSString(format: mainHTMLFormat, arguments: $0)) as String } return assembledHTMLString } Wondering where is hexString property of UIColor coming from? – Read about the Power of Extensions.

Configure WKWebView

You can configure it on your own. But if you don't know how to disable zooming, here is some help: webView.scrollView.delegate = self extension TutorialViewController: UIScrollViewDelegate { func viewForZooming(in scrollView: UIScrollView) -> UIView? { return nil // Just return nil here } } When you have the assembled HTML string, there is not much left to do: webView.loadHTMLString(assembledHTMLString, baseURL: Bundle.main.bundleURL)
This all may seem overcomplicated to you, but once you implement the logic, you will have a very useful tool.

Saturday, February 3, 2018

Changing view's type on the Storyboard


Suppose the design of your app changed, and now you need to replace the Table View with a Collection View keeping all the constraints along with views hierarchy.
Drop a new View Controller on the storyboard and put a Collection View inside. Rename it in the left panel (called Document Outline). Name it "The Replacement" so you will be able recognize it later. Now switch to the Source Code through the Open As.
Now the storyboard looks like XML markup. Find the Table View you need to replace, it will be scoped within the tableView tag.


Copy its id (example: id="8Oa-xL-ums"). It points to the view in constraints and outlets. Now find the new Collection View under the collectionView tag.


Copy everything including the enclosing tags: <collectionView ...</collectionView> and paste it instead of the tableView. Replace Collection View's id with the value you copied from the Table View. Before switching back to Interface Builder you need to clean up the storyboard. Remove the scene of the temporary View Controller that you created at the beginning of the tutorial. Delete everything between tags and the preceding comment: <!--View Controller><scene ...</scene>. If you don't do this you will have an error because of duplicated id.


Now you will have the new Collection View constrained like the Table View but misplaced, because it's was copied with the rect.
Click Update Frames and enjoy the result!

Here is the list of storyboard tags for different UI classes. Who knows, may be it will be useful.

arscnView ARSCNView
arskView ARSKView
glkView GLKView
mapView MKMapView
mtkView MTKView
sceneKitView SCNView
skView SKView
activityIndicatorView UIActivityIndicatorView
button UIButton
collectionView UICollectionView
datePicker UIDatePicker
imageView UIImageView
label UILabel
navigationBar UINavigationBar
pageControl UIPageControl
pickerView UIPickerView
progressView UIProgressView
scrollView UIScrollView
searchBar UISearchBar
segmentedControl UISegmentedControl
slider UISlider
stackView UIStackView
stepper UIStepper
switch UISwitch
tabBar UITabBar
tableView UITableView
textField UITextField
textView UITextView
toolbar UIToolbar
view UIView
containerView UIView (with embedded View Controller)
visualEffectView UIVisualEffectView
webView UIWebView
wkWebView WKWebView

How to Record Calls on iPhone