WWDC | Andy Ibanez https://www.andyibanez.com Teaching you cool stuff since 2012. Mon, 19 Aug 2019 22:08:54 +0000 en-US hourly 1 https://wordpress.org/?v=4.9.10 39653125 WWDC Keynote Thoughts https://www.andyibanez.com/wwdc-keynote-thoughts/ https://www.andyibanez.com/wwdc-keynote-thoughts/#respond Mon, 13 Jun 2016 16:39:17 +0000 https://www.andyibanez.com/?p=528 (Yes, I just copied Erica Sadun’s idea). This post will be update as the keynote goes by. (I will have lunch midway through the keynote, so I will be at least 15 minutes late at some point). ——— All times are EST. 12:52 PM: The stream seems to be finally up. 1:02 PM: Yes, talking […]

The post WWDC Keynote Thoughts appeared first on Andy Ibanez.

]]>
(Yes, I just copied Erica Sadun’s idea).

This post will be update as the keynote goes by.

(I will have lunch midway through the keynote, so I will be at least 15 minutes late at some point).

———

All times are EST.

12:52 PM: The stream seems to be finally up.
1:02 PM: Yes, talking about the Orlando tragedy is needed. I’m sure it hit Tim harder than others.
1:05 PM: That’s a lot of scholarships. I wish I could get that scholarship myself. Welp just gonna save up and go there someday…
1:09 PM: It was probably a good idea to avoid talking about the numbers. Jumping into OS features less than 10 minutes in.
1:11 PM: You are telling me watchOS 3.0 will make my watch usable beyond notifications? MADNESS. Neat change to the side button too.
1:12 PM: Doing this live is hard, so I will just edit this post later haha.

———–

5:20 PM:

SiriKit

So out of everything that has been announced, I’m excited for a lot of it.

Siri APIs of course. This is what I have been hoping for for years. Unfortunately, after further reading in the docs, it looks like it’s not possible to do much with it right now. SiriKit is designed to work with certain domains:

  • Audio or video calling
  • Messaging
  • Sending or receiving payments
  • Searching photos
  • Booking a ride
  • Managing workouts

At least at first, apps that adopt SiriKit will be limited to those domains.

Proactive Suggestions

Craig previewed a feature where QuickType is more useful and proactive than ever. It’s neat, and apps can expand on this. If your app has conceptual data it can provide to other apps, you can do so with these APIs. They are introduced in new properties of the UITextInputTraits class.

Apple Opens App Messages to Developers

I will go ahead and say meh to this one. All the visual woo is not too attractive for me. I could live without it. Stickers have always been a gimmick that I have never used. The potential of actual third party app integration is definitely neat, but I live in a country where WhatsApp is the norm, and nobody utilises iMessage. If I had to rate the new Messages announcements, I’d give them a 4/10. 4 being the only actual helpful stuff for developers (no stickers, no fancy features, just SDKs).

User Notifications

Apple is killing the old notification APIs in favor of this. I have no complaints. They are incredibly cool. This is probably one of the first things I will start playing with.

Speech Recognition

Very nifty framework. You can recognise speech from your own voice and even recorded audio. Writing a quick app to do this for me will me finish a lot of college of college homework.

Widget Enhancements

Absolutely cool. I like the idea of having my own widgets on search. Also how they appear when peek and popping on app icons. I see a lot of potential for this.

There’s a Whole Bunch of Extension Points

The amount of extension points has at least doubled since iOS 8:

  • Call Directory
  • Intents
  • Intents UI
  • Messages
  • Notification Content
  • Notification Service
  • Sticker Pack

Some of these are outright meh and the others do look helpful. I have yet to read an them though. That Call Directory Extension Points looks interesting. It might be something I asked Apple for back in 2011.

5:48 PM EDIT: Right, Call Directory is most likely the thing Craig showed where you can hook into calls to see if they are spam, or really extend them to do anything else with whatever number you grabbed.

Misc

Developers will finally have access to RAW camera data from the iOS camera. I love taking mobile pictures, and I currently use a Samsung Galaxy S7 Edge for most of my pictures. It looks like that could be changing soon.

That’s it for now. This post may or may not be edited later.

The post WWDC Keynote Thoughts appeared first on Andy Ibanez.

]]>
https://www.andyibanez.com/wwdc-keynote-thoughts/feed/ 0 528
WWDC 2015: Introducing Search APIs. https://www.andyibanez.com/wwdc-2015-introducing-search-apis/ https://www.andyibanez.com/wwdc-2015-introducing-search-apis/#respond Sat, 27 Jun 2015 20:51:40 +0000 https://www.andyibanez.com/?p=371 Following last week’s text summary of WWDC 2015’s What’s new in Swift, now I will cover the new (and arguably one of the most interesting new) things Apple talked about at WWDC. The original video can be found on both Apple’s WWDC site or on YouTube. Your app can now be tightly integrated with Spotlight, […]

The post WWDC 2015: Introducing Search APIs. appeared first on Andy Ibanez.

]]>
Following last week’s text summary of WWDC 2015’s What’s new in Swift, now I will cover the new (and arguably one of the most interesting new) things Apple talked about at WWDC. The original video can be found on both Apple’s WWDC site or on YouTube.


Your app can now be tightly integrated with Spotlight, and developers choose what to index via Search API’s. The goal of search APIs is to bring content to your apps in a search context. So instead of results just showing up in Spotlight, but they also show up in Safari. As the user types, the OS shows results. With Search APIs we will be able to jump directly to content inside our apps. Public linking of your app can be publicly indexed and be seen by everyone who has an iOS device. This provides a whole new level of exposure to your app. You can index much than content: You can make navigation points and features inside your apps searchable. This is useful because Spotlight is used a lot to search apps.

If your user doesn’t have your app installed, Apple can serve results from their gigantic cloud index anyway. We developers can tag content as public, and when many people interact with it, it will be promoted to the cloud index, making it really discoverable. Apple also finds deep webs from the web.

There are three Search APIs. They are different but entirely related to each other. They have different use cases.

Search APIs

  • NSUserActivity (Viewed app content): Extension of the Handoff API. Users want to search for things they have seen in the past. NSUserActivity makes it easy to index that information and makes it searchable.
  • CoreSpotlight (Any App Content): Comprehensively indexing any content inside your app. Gives you low level access to the index in the device. You can add and remove items. Best way to index any private content you have inside your app for your user.
  • Web Markup (App Content on Web): For apps that mirror their content on a website. You can simply mark your content for deep links and Apple will crawl it and add it to their public index.

The rest of the video covers 5 points:

  1. NSUserActivity
  2. CoreSpotlight
  3. Web Markup
  4. Achieving Best Results
  5. User Guides

NSUserActivity

Background: This API was introduced in iOS 8 to implement Handoff. Captures application state that can be restored later.

In iOS 9, NSUserActivities are indexed and searchable in iOS search and Safari. You can associate metadata with your activities, so you can describe your activities. When users engage with your search results, your app will be launch and pass the activity associated with that result. So you can continue restoring the state bringing the user back to their content.

NSUserActivity APIs

There are now APIs to enable index, public indexing, and handoff support.

To describe your activity, you give your activity:

A title: Used for indexing and display in search results.
Keywords: Describe activity, also added to the index.
contentAttributeSet: Makes it easy to describe the activity fully, setting property
expirationDate: To only be shown until a certain date.
webpageUrl: If your app supports Safari universal links.

To create an activity:

var activity: NSUserActivity = NSUserActivity(activityType: "com.yummly.browseRecipe") // You register this type to tell the system what kind of activities your app can handle. Recommended to use reverse DNS notation.
activity.title = "Baked Potato Chips"

// Contains the information we need to recreate the state.
activity.userInfo = ["id": "http://www.yummly.com/recipe/BPC-983195"]

// Enable on-Device indexing.
activity.eligibleForSearch = true

// This activity represents the user's current activity.
activity.becomeCurrent()

When a user taps your results results, a UIApplicationDelegate method is called.

func application(UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: [AnyObject]? -> Void) -> Bool {

	if userActivity.activityType == "com.yummly.browseRecipe" {
		// Restore state for userActivity and userInfo
	}

	return true
}

NSUserActivity is great to let your users go back to something they already visited. But Apple wanted to take it further, and can do with public indexing.

To do this, you create activities as users navigate your app and designate them as public. As users engage with the search results, they get indexed in the cloud index. If your app can be restored in web, you can increase the discoverability.

To mark an activity as public:

var activity: NSUserActivity = NSUserActivity(activityType: "com.yummly.browseRecipe")
activity.userInfo = ["id": "http://www.yummly.com/recipe/BPC-983195"]
activity.eligibleForPublicIndexing = true // Right here!
activity.eligibleForSearch = true
activity.becomeCurrent()

Of course, just by designating the content as public, it doesn’t mean it will be immediately shared with a cloud index. It has to be engaged with by many users.

There’s additional benefits to this API, such as getting Handoff, Siri suggestions and Siri smart reminders. This allows users to remind Siri about interesting content in your apps. When they do, the activity of your app is embedded in the reminder.

CoreSpotlight

A brand new framework in iOS 9. Provides a database-like API, so you can add and remove items. Can be used for indexing any content.

CoreSpotlight API

CSSearchableItem represents an item you wish to index. We associate a CSSearchableItemAttributeSet to said item, by describing properties. We pass the searchable item to the CSSearchableIndex and the item will be ready to be searched.

// Create attribute set and populate with metadata.
let attributeSet = CSSearchableItemAttributeSet(itemContentType: kUTTypeImage as String)

attributeSet.title = "Haleakala Sunrise"
attributeSet.contentDescription = "May 12, 2015 Maui, Hawaii"

// Create an item with unique identifier: domainIdentifier is used to group items
let item = CSSearchableItem(uniqueIdentifier: "1", domainIdentifier: "album-1", attributeSet: attributeSet)

// Index the item
CSSearchableItem.defaultSearchableIndex().indexSearchableItems([item]) { error in
	if error != nil {
		print(error?.localizedDescription)
	} else {
		print("Item indexed!")
	}
}

When a user taps your results, the same UIApplicationDelegate that got called when dealing with NSUserActivity will be called. But we know the results come from spotlight because the activity type is CSSearchableItemActionType:

func application(UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: [AnyObject]? -> Void) -> Bool {

	if userActivity.activityType == CSSearchableItemActionType {
		let uniqueIdentifier = userActivity.userInfo?[CSSearchableItemActivityIdentifier] as? String
		// use the identifier
	}

	return true
}

Maintaining your Index

Index supports updating items. You can do this with the same method you use to add items but passing updated metadata.

You can also delete items. There’s many ways to do this:

By identifier: You can pass an array of identifiers to delete to the deleteSearchableItemsWithIdentifiers method.
By domain identifier: You can pass an array of domain identifiers to the deleteSearchableItemsItemsWithDomainIdentifiers method.
You can also delete all the items by calling deleteAllSearchableItemsWithCompletionHandler.

CoreSpotlight Additional Features

Batching
CSSearchableIndexDelegate
Extension
Data Protection Classes

Web Markup

The key is the deeplink.

Apple has their own bot called Apple Bot. You don’t have to do anything.

To index your content, there’s four steps:

1. Making sure Apple can discover and index your website.
2. Ensuring your website contains markup for deeplinks.
3. Make sure your app can handle opening those deeplinks.
4. (Optional but recommended) add markup for structured data.

The easiest way to make your content discoverable is to submit your support or marketing URL when submitting your app.
Your website must have markup for deeplinks. The most popular way is to use smart app banners.

iOS 9 has universal links, which are better than smart banners. They have several advantages over custom URL schemes, such as:
– They are unique. Other apps can’t use them.
– Secure. Apple checks that your app and the website are really linked together.
– User can choose if the app should open the app or the website.
– They are universal. Can be used for web content as well as your app’s content.

You can also use Twitter cards and Facebook app links to link your app and site together.

(The lecturer recommends we check out the Seamless Linking to your App session).

To make sure your app can open deeplinks:

func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool {
	// In this example, the URL is http://www.example.com/profile/?123
	if let components = NSURLComponents(URL: url, resolvingAgainstBaseURL: true), let path = components.path, let query = components.query {
		if path == "/profile" {
			// Pass the profile ID from the URL, to the view controller
			return profileViewController.loadProfile(query)
		}
	}
}

Structured Data

Let’s Apple understand and parse your information for their results.

They go beyond just a title and a description.
Results can contain images, structured data, and even actions.
They are engaging to your user and improve your ranking.

There’s many ways for structured data. Schema.org and others can be parsed by the Apple Bot.

Actions

– Dialling a phone number
– Getting directions
– Play audio or video.

Testing Tools

Apple will have testing tools to test deeplink and structured data.

Summary

CoreSpotlight is for private data on the device.
Web Markup is for apps that have their content on the web.
NSUserActivity for both Public and Private content, and to index navigation points within your app.

You can adopt them all in the same app. You need to link your content with an ID. The obvious ID for these items is the URL, when using all the APIs.

Ranking. Apple cares about URL popularity, Activities, and engagements.

Search will down-rank or suppress poor results.
Malicious content will be penalised.

User Guidelines:

– Richer results cause more engagement.
– Try to use keywords.
– When user taps the result, take them directly to the result. For the nasty developers, this means no annoying full screen ads, and no long load times.
– Try to add synonyms, as users like typing short search results.

What to index:
– Your app content. Content user has viewed, curated, created.
– Navigation Points.
– New content arrived.

The post WWDC 2015: Introducing Search APIs. appeared first on Andy Ibanez.

]]>
https://www.andyibanez.com/wwdc-2015-introducing-search-apis/feed/ 0 371
WWDC 2015: What’s new in Swift 2. https://www.andyibanez.com/wwdc-2015-whats-new-in-swift-2/ https://www.andyibanez.com/wwdc-2015-whats-new-in-swift-2/#respond Sat, 20 Jun 2015 20:55:29 +0000 https://www.andyibanez.com/?p=367 This is a text summary of the What’s new in Swift 2 video (Session 106) posted by Apple. This is a recording of a session at WWDC 2015. You can watch this video in Apple’s WWDC Page. Additionally, if you can’t view the video (because you don’t have an Apple device, etc), Apple has also […]

The post WWDC 2015: What’s new in Swift 2. appeared first on Andy Ibanez.

]]>
This is a text summary of the What’s new in Swift 2 video (Session 106) posted by Apple. This is a recording of a session at WWDC 2015. You can watch this video in Apple’s WWDC Page. Additionally, if you can’t view the video (because you don’t have an Apple device, etc), Apple has also posted this vid in their YouTube page.

This post covers everything important from the aforementioned video. I personally learn much better when I read instead of watching a video, so initially I was going to write this for myself, but nothing wrong in releasing it for everyone else, right?


Philosophies behind Swift 2:

  1. Refine language and tools fundamentals.
  2. Affordances for writing robust and safe code.
  3. Code Beauty

The video covers 5 aspects of Swift:

  1. Fundamentals
  2. Pattern Matching
  3. Availability Checking
  4. Protocol Extensions
  5. Error Handling

Fundamentals

Enums

Enums carry enough reflection information, that you can print them and they work great.

enum Animals {
	case Dog, Cat, Troll, Dragon
}

let a = Animals.Dragon
print(a)

Prints:

Animal.Dragon

Associated Values in Enums

They are the perfect model for discriminating union, great when you have two values of different values you want to store in one thing.

enum Either<T1, T2> {
	case First(T1)
	case Second(T2)
}

This didn’t work in previous versions of Swift.

Recursive Enums

enum Tree<T> {
	case Leaf(T)
	indirect case Node(Tree, Tree)
}

By using the “indirect” keyword where recursion happens, you are allowed to have recursive enums. This also works great with Pattern Matching.

Scoping

“do” Statement

do {
	let a = Animals.troll
}

This is more useful in Error Handling.

The do-while loops has been renamed to repeat.

repeat {
	println("eyoo")
} while i < 5

Option Sets

You have seen them as or’s before.

viewAnimationOptions = .Repeat | .CurveEaseIn | .TransitionCurlUp

In Swift 2, they have a different syntax. In Swift 1.2, a First Class Set Type. Option Sets and Sets are now formed with this new syntax:

viewAnimationOptions = [.Repeat, .CurveEaseIn, .TransitionCurlUp]

This means you can use empty brackets to create an empty set, and checking if it contains a value is much nicer too:

if viewAnimationOptions.contains(.TransitionCurlUp) {
	
}

You can also define your own option sets in a much easier way: Define your own struct type, have it conform to the OptionSetType protocol, and define some storage to hold your tips, and the define the elements you want for your option set.

struct MyFontStyle : OptionSetType {
	let rawValue: Int
	static let Bold 		 = MyFontStyle(rawValue: 1)
	static let Italic  		 = MyFontStyle(rawValue: 2)
	static let Underline 	 = MyFontStyle(rawValue: 4)
	static let StrikeThrough = MyFontStyle(rawValue: 8)
}

myFont.style = []
myFont.style = [.Underline]
myFont.style = [.Bold, .Italic]

if myFont.style.contains(.StrikeThrough) {

}

(It is recommended to watch the Protocol-Oriented Programming in Swift session).

Functions and Methods

Swift 1 was following the steps of Objective-C:

– No label for global functions
– Labels for second argument (and later) in methods.

In Swift 2, functions and methods have the same declaration syntax, so when calling global functions, you provide labels by default. This doesn’t change in imported C and Objective-C APIs.

Argument Label Controls

The “_” syntax in method declaration to avoid specifying a different label name than internal parameter name.

func save(_ name: String, encrypt encrypt: Bool)

You can of course replace the underscore for a label name. The function definition above is what Swift uses by convention (first parameter doesn’t need a label, everything else does.

Swift 2 has a much simpler model for the whole argument label thing:

– Consistency between functions and methods.
– No special rules for defaulted parameters.
– The “#” syntax has been removed. In Swift 1, you used the # syntax to specify the label and parameter name at the same time. Therefore doing this is no longer possible in Swift 2:

func save(_ name: String, #encrypt: Bool)

Unit Testing

Tests can access the internal and public symbols when using the keyword “@testable”.

@testable
import MyApp

Rich Playgrounds

You can create much nicer documentation using Markdown. From font styles to images, almost everything can be included.

Swift Fundamentals not Covered:

– Default implementations in Protocols.
– C Function pointers + closures.
– Recursive nested functions.
– if/do labeled breaks.
– SIMD Vectors.
– Mirrors API.
– readLine().
– @nonobjc

Pattern Matching

First used in the “if let” statement. The problem is you can nest them to deep pyramids and it’s hard to understand. Swift 2 introduces Compound Conditions to avoid this:

func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
	if let dest = segue.destinationViewController as? BlogViewController
	   let blogIndex = tableView.indexPathForSelectedRow()?.row
	   where segue.identifier == blogSegueIdentifier {
	       dest.blogName = swiftBlogs[blogIndex]
	   }
}

You can check multiple optionals and even conditions.

Patterns for Early Exits

You can force-unwrap optionals early so you don’t find yourself doing that too often, specially if your code is too long. This won’t cause a crash.

func process(json: AnyObject) -> Either<Person, String> {
	let name: String! = json["name"] as? String
	if let name == nil {
		return .Second("missing name")
	}
	let year: Int! = json["year"] as? Int
	if year == nil {
		return .Second("missing year")
	}
	let person = processPerson(name, year)
	return .First(person)
}

But this is ugly too. To exit early, you can now use the “guard” statement.

guard let name = json["name"] as? String else {
	return .Second("missing name")
}

It guarantees else exits the current scope.

The code for process now looks much nicer:

func process(json: AnyObject) -> Either<Person, String> {
	guard let name = json["name"] as? String else {
		return .Second("missing name")
	}
	guard let year = json["year"] as? Int else {
		return .Second("missing name")
	}
	let person = processPerson(name, year)
	return .First(person)
}

This works nice with multiple conditions, so the code above can be made even nicer:

func process(json: AnyObject) -> Either<Person, String> {
	guard let name = json["name"] as? String, guard let year = json["year"] as? Int else {
		return .Second("bad input")
	}
	let person = processPerson(name, year)
	return .First(person)
}

Switches

They have always been the best thing of pattern matching. But they are heavy when you only want to check one condition. So the following:

switch bar() {
	case .MyEnumCase(let value) where value !+ 42:
	doThing(value)

	default: break
}

Can be better written this way in Swift 2:

if case .MyEnumCase(let value) = bar() where value != 42 {
	doThing(value)
}

for… in Filtering

Swift 2 gives you a very nice way to filter results in a for… in loop, and also allows you to use pattern matching in for … in loops:

for value in mySequence where value != "" {
	doThing(value)
}
for case .MyEnumCase(let value) in enumValues {
	doThing(value)
}

Other Improvements

– x? pattern for optionals.
– Improvement exhaustiveness checker.
– Unreachable case warning.

API Availability Checking

extension NSButton {
	@available(OSX 10.10.3)
	var springLoaded: Bool
}

You can check for versions like this:

override func awakeFromNib() {
	if #available(OSX 10.10.3, *) {
		dropButton.springLoaded = true
	}
}

You could also use the guard statement.

Protocol Extensions

You can extend protocols themselves. In the video, it is pointed that something you add to an array may apply to all collection types, so we are shown we can extend protocols themselves. For example this:

extension CollectionType {
	func countIf(match: Element -> Bool) -> Int {
		var n = 0
		for value in self {
			if match(value) { n++ }
		}
		return n
	}
}

Is added to everything that implements CollectionType.

Global generic algorithms are becoming methods.

Error Handling

The main purpose is to help get rid of the overflow of NSErrors everywhere.

There are two components to deal with Errors in Swift. First, the try keyboard is used before an API that can throw an error. Second, every method that throws something needs to have the throws keyboard after the parenthesis in the method name. Any code that is preceded by throw, must be inside a do, and that must be accompanied by a catch (which can be used pattern matching on). Using Pattern matching allows you to catch different kinds of errors.

func preflight() throws {

}
func preflight() -> Bool {
	do {
		try url.checkResourceIsReachable()
		resetState()
		return true
	} catch NSURLError.FileDoesNotExist {
		return true
	} catch let error {
		return false
	}
}

You can also use the fatalError() function for extreme scenarios. Used when you can’t recover from the error.

To mark something as Impossible Errors, follow the try keyword with a !. If your program throws an error in that situation, your program will crash.

func preflight() {
	try! url.checkResourceIsReachable()
	resetState()
}

You can throw anything whose type conforms to ErrorType.

Enums are great to conform to ErrorType.

enum DataError: ErrorType {
	
}

You can make your function do something at the end of execution. A defer statement creates an action that gets called when exciting the current scope. That means that instead of doing something like this:

func process(json: AnyObject) -> Either<Person, String> {
	delegate?.didBeginReadingSale()
	guard let name = json["name"] as? String else {
		delegate?.didEndReadingSale()
		throw DataError.MissingName
	}
	guard let year = json["year"] as? Int else {
		delegate?.didEndReadingSale
		return .Second("missing name")
	}
	let person = processPerson(name, year)
	delegate?.didEndReadingSale()
	return .First(person)
}

You can do this:

func process(json: AnyObject) -> Either<Person, String> {
	delegate?.didBeginReadingSale()
	defer{ delegate?.didEndReadingSale() }
	guard let name = json["name"] as? String else {
		throw DataError.MissingName
	}
	guard let year = json["year"] as? Int else {
		return .Second("missing name")
	}
	let person = processPerson(name, year)
	return .First(person)
}

The post WWDC 2015: What’s new in Swift 2. appeared first on Andy Ibanez.

]]>
https://www.andyibanez.com/wwdc-2015-whats-new-in-swift-2/feed/ 0 367