Skip to content

Instantly share code, notes, and snippets.

@dlevi309
Last active August 1, 2022 04:02
Show Gist options
  • Save dlevi309/d4c7ba353faea5b3e01380f0290e8c75 to your computer and use it in GitHub Desktop.
Save dlevi309/d4c7ba353faea5b3e01380f0290e8c75 to your computer and use it in GitHub Desktop.
Compact database of all the talks, developer sessions and documentation guides given stretching back from WWDC14 to WWDC20. The assets included per session are what was made available (like pdf slides, direct download links, HLS + m3u8, etc.) Also displays scheduled deletion dates
This file has been truncated, but you can view the full file.
{
"updated": "2020-11-27T10:39:35-08:00",
"snapshotId": 1025,
"events": [
{
"name": "WWDC20",
"current": false,
"id": "wwdc2020",
"webUrlKey": "wwdc20",
"startTime": "2020-06-22T10:00:00-07:00",
"endTime": "2020-06-26T17:00:00-07:00",
"imagesPath": "https://devimages-cdn.apple.com/wwdc-services/images/49",
"hashtag": "#wwdc20",
"imageURL": "https://devimages-cdn.apple.com/wwdc-services/images/topic-glyphs/Source-WWDC.pdf",
"macImageURL": "https://devimages-cdn.apple.com/wwdc-services/images/topic-glyphs/mac/Events-WWDC.pdf",
"sortOrder": "groupedPublishDateAscending",
"isSearchable": true,
"isBrowsable": true
},
{
"name": "News",
"current": true,
"id": "news",
"webUrlKey": "news",
"startTime": "2020-01-01T00:00:00+00:00",
"endTime": "2025-01-01T00:00:00+00:00",
"imagesPath": "https://devimages-cdn.apple.com/wwdc-services/images/82",
"hashtag": "#developer",
"imageURL": "https://devimages-cdn.apple.com/wwdc-services/images/topic-glyphs/Source-News.pdf",
"macImageURL": "https://devimages-cdn.apple.com/wwdc-services/images/topic-glyphs/mac/Discover-News.pdf",
"sortOrder": "ungroupedPublishDateDescending",
"isSearchable": true,
"isBrowsable": false
},
{
"name": "Articles",
"current": false,
"id": "articles",
"webUrlKey": "articles",
"startTime": "2020-01-01T00:00:00+00:00",
"endTime": "2030-01-01T00:00:00+00:00",
"imagesPath": "https://devimages-cdn.apple.com/wwdc-services/images/117",
"hashtag": "#developerApp",
"imageURL": "https://devimages-cdn.apple.com/wwdc-services/images/topic-glyphs/Source-TechTalks.pdf",
"macImageURL": "https://devimages-cdn.apple.com/wwdc-services/images/topic-glyphs/mac/Events-TechTalks.pdf",
"sortOrder": "ungroupedPublishDateDescending",
"isSearchable": true,
"isBrowsable": true
},
{
"name": "WWDC19",
"current": false,
"id": "wwdc2019",
"webUrlKey": "wwdc19",
"startTime": "2019-06-03T10:00:00-07:00",
"endTime": "2019-06-07T18:00:00-07:00",
"imagesPath": "https://devimages-cdn.apple.com/wwdc-services/images/48",
"hashtag": "#developerapp",
"imageURL": "https://devimages-cdn.apple.com/wwdc-services/images/topic-glyphs/Source-WWDC19.pdf",
"macImageURL": "https://devimages-cdn.apple.com/wwdc-services/images/topic-glyphs/mac/Events-WWDC.pdf",
"sortOrder": "groupedPublishDateAscending",
"isSearchable": true,
"isBrowsable": true
},
{
"name": "WWDC18",
"current": false,
"id": "wwdc2018",
"webUrlKey": "wwdc18",
"startTime": "2018-06-04T10:00:00-07:00",
"endTime": "2018-06-08T17:00:00-07:00",
"imagesPath": "https://devimages-cdn.apple.com/wwdc-services/images/42",
"hashtag": "#developerapp",
"imageURL": "https://devimages-cdn.apple.com/wwdc-services/images/topic-glyphs/Source-WWDC18.pdf",
"macImageURL": "https://devimages-cdn.apple.com/wwdc-services/images/topic-glyphs/mac/Events-WWDC.pdf",
"sortOrder": "groupedPublishDateAscending",
"isSearchable": true,
"isBrowsable": true
},
{
"name": "Developer Insights",
"current": false,
"id": "insights",
"webUrlKey": "videos/play/insights",
"startTime": "2018-05-07T00:00:00+00:00",
"endTime": "2018-05-07T00:00:00+00:00",
"imagesPath": "https://devimages-cdn.apple.com/wwdc-services/images/44",
"hashtag": "#developerapp",
"imageURL": "https://devimages-cdn.apple.com/wwdc-services/images/topic-glyphs/Source-DeveloperInsights.pdf",
"macImageURL": "https://devimages-cdn.apple.com/wwdc-services/images/topic-glyphs/mac/Other-Generic.pdf",
"sortOrder": "ungroupedPublishDateDescending",
"isSearchable": true,
"isBrowsable": true
},
{
"name": "Tech Talks",
"current": false,
"id": "tech-talks",
"webUrlKey": "videos/play/tech-talks",
"startTime": "2017-07-01T00:00:00+00:00",
"endTime": "2025-01-01T00:00:00+00:00",
"imagesPath": "https://devimages-cdn.apple.com/wwdc-services/images/8",
"hashtag": "#developerapp",
"imageURL": "https://devimages-cdn.apple.com/wwdc-services/images/topic-glyphs/Source-TechTalks.pdf",
"macImageURL": "https://devimages-cdn.apple.com/wwdc-services/images/topic-glyphs/mac/Events-TechTalks.pdf",
"sortOrder": "ungroupedPublishDateDescending",
"isSearchable": true,
"isBrowsable": true
},
{
"name": "WWDC17",
"current": false,
"id": "wwdc2017",
"webUrlKey": "wwdc17",
"startTime": "2017-06-05T10:00:00-07:00",
"endTime": "2017-06-09T15:30:00-07:00",
"imagesPath": "https://devimages-cdn.apple.com/wwdc-services/images/7",
"hashtag": "#developerapp",
"imageURL": "https://devimages-cdn.apple.com/wwdc-services/images/topic-glyphs/Source-WWDC17.pdf",
"macImageURL": "https://devimages-cdn.apple.com/wwdc-services/images/topic-glyphs/mac/Events-WWDC.pdf",
"sortOrder": "groupedPublishDateAscending",
"isSearchable": true,
"isBrowsable": true
},
{
"name": "WWDC16",
"current": false,
"id": "wwdc2016",
"webUrlKey": "wwdc16",
"startTime": "2016-06-13T10:00:00-07:00",
"endTime": "2016-06-17T17:40:00-07:00",
"imagesPath": "https://devimages-cdn.apple.com/wwdc-services/images/1",
"hashtag": "#developerapp",
"imageURL": "https://devimages-cdn.apple.com/wwdc-services/images/topic-glyphs/Source-WWDC16.pdf",
"macImageURL": "https://devimages-cdn.apple.com/wwdc-services/images/topic-glyphs/mac/Events-WWDC.pdf",
"sortOrder": "groupedPublishDateAscending",
"isSearchable": true,
"isBrowsable": true
},
{
"name": "WWDC15",
"current": false,
"id": "wwdc2015",
"webUrlKey": "wwdc15",
"startTime": "2015-06-08T10:00:00-07:00",
"endTime": "2015-06-12T16:10:00-07:00",
"imagesPath": "https://devimages-cdn.apple.com/wwdc-services/images/2",
"hashtag": "#developerapp",
"imageURL": "https://devimages-cdn.apple.com/wwdc-services/images/topic-glyphs/Source-WWDC15.pdf",
"macImageURL": "https://devimages-cdn.apple.com/wwdc-services/images/topic-glyphs/mac/Events-WWDC.pdf",
"sortOrder": "groupedPublishDateAscending",
"isSearchable": true,
"isBrowsable": true
},
{
"name": "WWDC14",
"current": false,
"id": "wwdc2014",
"webUrlKey": "wwdc14",
"startTime": "2014-06-02T10:00:00-07:00",
"endTime": "2014-06-06T12:30:00-07:00",
"imagesPath": "https://devimages-cdn.apple.com/wwdc-services/images/3",
"hashtag": "#developerapp",
"imageURL": "https://devimages-cdn.apple.com/wwdc-services/images/topic-glyphs/Source-WWDC14.pdf",
"macImageURL": "https://devimages-cdn.apple.com/wwdc-services/images/topic-glyphs/mac/Events-WWDC.pdf",
"sortOrder": "groupedPublishDateAscending",
"isSearchable": true,
"isBrowsable": true
}
],
"contents": [
{
"id": "wwdc2020-10834",
"staticContentId": 3368,
"eventContentId": 10834,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=jnakvxnn",
"description": "",
"title": "Connect with Core Data",
"articleID": "6B25688D-1F45-4E5A-9B18-E3010B4E7ED1",
"articlePermalinkKey": "jnakvxnn",
"originalPublishingDate": "2020-06-22T00:00:54-07:00",
"publishingExpiryDate": "2025-06-22T01:42:56-07:00",
"platforms": [
"iOS",
"macOS"
],
"topicIds": [
],
"type": "Article",
"images": [
"square",
"wide"
],
"related": {
"activities": [
"wwdc2020-10724",
"wwdc2020-10725",
"wwdc2020-10726"
]
}
},
{
"id": "wwdc2020-10222",
"staticContentId": 3683,
"eventContentId": 10222,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10222",
"description": "Build enterprise apps for your employees to help them solve problems and streamline everyday tasks. See how to build custom apps designed for your workforce. Learn how to identify great mobile use cases, have your employees drive the design process, use key Apple frameworks, and rapidly iterate with Xcode.",
"title": "Create custom apps for employees",
"originalPublishingDate": "2020-06-26T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS"
],
"keywords": [
"enterprise",
"interview",
"iterations",
"iterative"
],
"topicIds": [
70
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10222/7/8EB4D4CB-2C1F-43E4-B544-53CC7495139A/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10222/7/8EB4D4CB-2C1F-43E4-B544-53CC7495139A/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10222/6/EE174886-CF35-41EE-A016-35C9748259BD/transcripts/wwdc2020-10222-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10222/7/8EB4D4CB-2C1F-43E4-B544-53CC7495139A/wwdc2020_10222_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10222/7/8EB4D4CB-2C1F-43E4-B544-53CC7495139A/wwdc2020_10222_sd.mp4",
"duration": 890
},
"related": {
"activities": [
"wwdc2020-10638"
],
"resources": [
1237,
1236
]
}
},
{
"id": "wwdc2020-10667",
"staticContentId": 3532,
"eventContentId": 10667,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10667",
"description": "Apple Business Manager is the best way to manage and deploy business apps to your employees and customers. Whether you're a developer, business owner, or IT administrator, we'll showcase the benefits of Custom apps for each role and provide guidance on each step in the process — from app creation to distribution.",
"title": "Custom app distribution with Apple Business Manager",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS"
],
"keywords": [
"education",
"enterprise",
"in-house",
"internal",
"vpp"
],
"topicIds": [
70
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10667/2/745F75A7-CDE9-438F-BB2C-EE1BF3E56CC7/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10667/2/745F75A7-CDE9-438F-BB2C-EE1BF3E56CC7/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10667/2/745F75A7-CDE9-438F-BB2C-EE1BF3E56CC7/transcripts/wwdc2020-10667-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10667/2/745F75A7-CDE9-438F-BB2C-EE1BF3E56CC7/wwdc2020_10667_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10667/2/745F75A7-CDE9-438F-BB2C-EE1BF3E56CC7/wwdc2020_10667_sd.mp4",
"duration": 1261
},
"related": {
"activities": [
"wwdc2020-10223",
"wwdc2020-10638",
"wwdc2020-10754",
"wwdc2020-10844",
"wwdc2019-304"
],
"resources": [
1131,
1130,
653,
410,
330,
329,
309
]
}
},
{
"id": "wwdc2020-10086",
"staticContentId": 3693,
"eventContentId": 10086,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10086",
"description": "Intelligence is a core part of building a great modern app. App extensions, Siri suggestions, voice, widgets, app clips — we’ve designed all of these features to help make everyday tasks easier for people who use our platforms. Learn about the origins of the intelligent system experience, and find out how integrating intelligently with the system can help make your app more convenient, relevant, and intuitive, making your features the focus.\r\n\r\nLearn more about designing for intelligence in the next part of our series, \"Discover new opportunities.\"",
"title": "Design for intelligence: Apps, evolved",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"keywords": [
"conversational interaction",
"design",
"discoverability",
"donations",
"extensions",
"intelligence",
"intelligent system experience",
"intents",
"intentsui",
"shortcuts",
"siri",
"sirikit",
"siri suggestions",
"suggestions",
"system intelligence",
"ui",
"user experience",
"voice"
],
"topicIds": [
39,
40,
21,
13,
6,
3
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10086/3/F5DA137E-B1E5-4180-96CC-2D6680E5996E/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10086/3/F5DA137E-B1E5-4180-96CC-2D6680E5996E/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10086/3/F5DA137E-B1E5-4180-96CC-2D6680E5996E/transcripts/wwdc2020-10086-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10086/3/F5DA137E-B1E5-4180-96CC-2D6680E5996E/wwdc2020_10086_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10086/3/F5DA137E-B1E5-4180-96CC-2D6680E5996E/wwdc2020_10086_sd.mp4",
"duration": 424
},
"related": {
"activities": [
"wwdc2020-10053",
"wwdc2020-10060",
"wwdc2020-10061",
"wwdc2020-10068",
"wwdc2020-10069",
"wwdc2020-10071",
"wwdc2020-10073",
"wwdc2020-10074",
"wwdc2020-10083",
"wwdc2020-10084",
"wwdc2020-10087",
"wwdc2020-10088",
"wwdc2020-10190",
"wwdc2020-10194",
"wwdc2020-10197",
"wwdc2020-10200",
"wwdc2020-10693",
"wwdc2020-10839",
"wwdc2020-10877",
"wwdc2020-10878",
"wwdc2020-10879",
"wwdc2020-10914",
"wwdc2020-10917",
"wwdc2020-10918",
"wwdc2020-10963",
"wwdc2020-10980"
],
"resources": [
1245,
1244
]
}
},
{
"id": "wwdc2020-10098",
"staticContentId": 3329,
"eventContentId": 10098,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10098",
"description": "Universal Links help people access your content, whether or not they have your app installed. Get the details on the latest updates for the Universal Links API, including support for Apple Watch and SwiftUI. Learn how you can reduce the size and complexity of your app-site-association file with enhanced pattern matching features like wildcards, substitution variables, and Unicode support. And discover how cached associated domains data will improve the initial launch experience for people using your app.",
"title": "What's new in Universal Links",
"originalPublishingDate": "2020-06-26T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"watchOS"
],
"keywords": [
"handoff",
"spotlight",
"universal link",
"universal links"
],
"topicIds": [
20,
18,
67
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10098/3/E024AF2B-1DDA-4974-AA48-4186E6F9E22D/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10098/3/E024AF2B-1DDA-4974-AA48-4186E6F9E22D/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10098/3/E024AF2B-1DDA-4974-AA48-4186E6F9E22D/transcripts/wwdc2020-10098-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10098/3/E024AF2B-1DDA-4974-AA48-4186E6F9E22D/wwdc2020_10098_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10098/3/E024AF2B-1DDA-4974-AA48-4186E6F9E22D/wwdc2020_10098_sd.mp4",
"duration": 1384
},
"related": {
"activities": [
"wwdc2020-10118",
"wwdc2020-10146",
"wwdc2020-10651",
"wwdc2020-10837",
"wwdc2020-10846",
"wwdc2019-717"
],
"resources": [
931,
930,
779,
515
]
}
},
{
"id": "wwdc2020-10088",
"staticContentId": 3694,
"eventContentId": 10088,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10088",
"description": "Learn how extensibility is key to surfacing the most important features of your app into new entry points of the operating system. And discover how — by breaking out of the constraints of a monolithic container — your app can see increased engagement through suggestions on the lock screen, in Calendar, and by enabling voice interactions.",
"title": "Design for intelligence: Discover new opportunities",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"keywords": [
"donations",
"intelligence",
"intelligent system experience",
"intents",
"intentsui",
"shortcuts",
"shortcuts app",
"siri event suggestions",
"sirikit",
"siri suggestions",
"suggestions",
"system intelligence",
"voice"
],
"topicIds": [
39,
40,
21,
13,
6,
3
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10088/3/F305AEBE-F447-4B36-A540-FA6C33F70969/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10088/3/F305AEBE-F447-4B36-A540-FA6C33F70969/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10088/3/F305AEBE-F447-4B36-A540-FA6C33F70969/transcripts/wwdc2020-10088-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10088/3/F305AEBE-F447-4B36-A540-FA6C33F70969/wwdc2020_10088_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10088/3/F305AEBE-F447-4B36-A540-FA6C33F70969/wwdc2020_10088_sd.mp4",
"duration": 311
},
"related": {
"activities": [
"wwdc2020-10053",
"wwdc2020-10060",
"wwdc2020-10061",
"wwdc2020-10068",
"wwdc2020-10069",
"wwdc2020-10071",
"wwdc2020-10073",
"wwdc2020-10074",
"wwdc2020-10083",
"wwdc2020-10084",
"wwdc2020-10086",
"wwdc2020-10087",
"wwdc2020-10190",
"wwdc2020-10194",
"wwdc2020-10197",
"wwdc2020-10200",
"wwdc2020-10839",
"wwdc2020-10877",
"wwdc2020-10878",
"wwdc2020-10879",
"wwdc2020-10914",
"wwdc2020-10917",
"wwdc2020-10918",
"wwdc2020-10963",
"wwdc2020-10980"
],
"resources": [
1247,
1246
]
}
},
{
"id": "wwdc2020-10089",
"staticContentId": 3460,
"eventContentId": 10089,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10089",
"description": "Find and fix rendering and optimization issues in your Core Image pipeline with Xcode environment variable. Discover how you can set the environment variable for visualizing your Core Image graphs. You'll learn how to generate Core Image graphs and how to interpret them to discover memory, color, and performance issues and better improve and optimize your Core Image pipeline.",
"title": "Discover Core Image debugging techniques",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS"
],
"keywords": [
"coreimage",
"graphics",
"image processing",
"metal",
"performance",
"video",
"xcode"
],
"topicIds": [
38,
31,
30,
27,
24
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10089/5/36633315-0427-4533-B65F-57E8A9804A81/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10089/5/36633315-0427-4533-B65F-57E8A9804A81/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10089/5/36633315-0427-4533-B65F-57E8A9804A81/transcripts/wwdc2020-10089-transcripts.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10089/5/36633315-0427-4533-B65F-57E8A9804A81/wwdc2020_10089_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10089/5/36633315-0427-4533-B65F-57E8A9804A81/wwdc2020_10089_sd.mp4",
"duration": 436
},
"related": {
"activities": [
"wwdc2020-10008",
"wwdc2020-10014",
"wwdc2020-10021",
"wwdc2020-10723"
],
"resources": [
1057,
1056,
32
]
}
},
{
"id": "wwdc2020-10090",
"staticContentId": 3463,
"eventContentId": 10090,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10090",
"description": "Make decoding and displaying ProRes content easier in your Mac app: Learn how to implement an optimal graphics pipeline by leveraging AVFoundation and VideoToolbox’s decoding capabilities. We’ll share best practices and performance considerations for your app, show you how to integrate Afterburner cards into your pipeline, and walk through how you can display decoded frames using Metal.",
"title": "Decode ProRes with AVFoundation and VideoToolbox",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"macOS"
],
"keywords": [
"av foundation",
"metal",
"performance",
"prores",
"video"
],
"topicIds": [
35,
31,
27
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Creating an AVAssetReader is pretty easy",
"startTimeSeconds": 461,
"endTimeSeconds": 475,
"language": "objectivec",
"code": "u003cspan class=\"syntax-comment\"u003e// Constructing an AVAssetReaderu003c/spanu003e\n\nu003cspan class=\"syntax-comment\"u003e// Create an AVAsset with an URL pointing at a local assetu003c/spanu003e\nu003cspan class=\"syntax-built_in\"u003eAVAssetu003c/spanu003e *sourceMovieAsset = [u003cspan class=\"syntax-built_in\"u003eAVAssetu003c/spanu003e assetWithURL:sourceMovieURL];\n\nu003cspan class=\"syntax-comment\"u003e// Create an AVAssetReader for the assetu003c/spanu003e\nu003cspan class=\"syntax-built_in\"u003eAVAssetReaderu003c/spanu003e *assetReader = [u003cspan class=\"syntax-built_in\"u003eAVAssetReaderu003c/spanu003e assetReaderWithAsset:sourceMovieAsset \n error:u0026amp;error];"
},
{
"title": "// Configuring AVAssetReaderTrackOutput",
"startTimeSeconds": 478,
"endTimeSeconds": 536,
"language": "objectivec",
"code": "u003cspan class=\"syntax-comment\"u003e// Configuring AVAssetReaderTrackOutputu003c/spanu003e\n\nu003cspan class=\"syntax-comment\"u003e// Copy the array of video tracks from the source movieu003c/spanu003e\nu003cspan class=\"syntax-built_in\"u003eNSArrayu003c/spanu003eu0026lt;u003cspan class=\"syntax-built_in\"u003eAVAssetTracku003c/spanu003e*u0026gt; *tracks = [sourceMovieAsset tracksWithMediaType:u003cspan class=\"syntax-built_in\"u003eAVMediaTypeVideou003c/spanu003e];\n \nu003cspan class=\"syntax-comment\"u003e// Get the first video tracku003c/spanu003e\nu003cspan class=\"syntax-built_in\"u003eAVAssetTracku003c/spanu003e *track = [sourceMovieVideoTracks objectAtIndex:u003cspan class=\"syntax-number\"u003e0u003c/spanu003e];\n\nu003cspan class=\"syntax-comment\"u003e// Create the asset reader track output for this video track, requesting ‘y416’ outputu003c/spanu003e\nu003cspan class=\"syntax-built_in\"u003eNSDictionaryu003c/spanu003e *outputSettings = @{ (u003cspan class=\"syntax-keyword\"u003eidu003c/spanu003e)kCVPixelBufferPixelFormatTypeKey :\n @(kCVPixelFormatType_4444AYpCbCr16) };\n\nu003cspan class=\"syntax-built_in\"u003eAVAssetReaderTrackOutputu003c/spanu003e* assetReaderTrackOutput\n= [u003cspan class=\"syntax-built_in\"u003eAVAssetReaderTrackOutputu003c/spanu003e assetReaderTrackOutputWithTrack:track\n outputSettings:outputSettings];\n\nu003cspan class=\"syntax-comment\"u003e// Set the property to instruct the track output to return the samples u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// without copying themu003c/spanu003e\nassetReaderTrackOutput.alwaysCopiesSampleData = u003cspan class=\"syntax-literal\"u003eNOu003c/spanu003e;\n \nu003cspan class=\"syntax-comment\"u003e// Connect the the AVAssetReaderTrackOutput to the AVAssetReaderu003c/spanu003e\n[assetReader addOutput:assetReaderTrackOutput];"
},
{
"title": "Running AVAssetReader",
"startTimeSeconds": 537,
"endTimeSeconds": 562,
"language": "objectivec",
"code": "u003cspan class=\"syntax-comment\"u003e// Running AVAssetReaderu003c/spanu003e\n\nu003cspan class=\"syntax-built_in\"u003eBOOLu003c/spanu003e success = [assetReader startReading];\n\nu003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e (success) {\n u003cspan class=\"syntax-built_in\"u003eCMSampleBufferRefu003c/spanu003e sampleBuffer = u003cspan class=\"syntax-literal\"u003eNULLu003c/spanu003e;\n \n u003cspan class=\"syntax-comment\"u003e// output is a AVAssetReaderOutputu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ewhileu003c/spanu003e ((sampleBuffer = [output copyNextSampleBuffer]))\n {\n CVImageBufferRef imageBuffer = u003cspan class=\"syntax-built_in\"u003eCMSampleBufferGetImageBufferu003c/spanu003e(sampleBuffer);\n \n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e (imageBuffer)\n {\n u003cspan class=\"syntax-comment\"u003e// Use the image buffer hereu003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// if imageBuffer is NULL, this is likely a marker sampleBufferu003c/spanu003e\n }\n }\n}"
},
{
"title": "Prepareing CMSampleBuffers for optimized RPC transfer",
"startTimeSeconds": 700,
"endTimeSeconds": 717,
"language": "objectivec",
"code": "u003cspan class=\"syntax-built_in\"u003eAVAssetReaderTrackOutputu003c/spanu003e* assetReaderTrackOutput\n= [u003cspan class=\"syntax-built_in\"u003eAVAssetReaderTrackOutputu003c/spanu003e assetReaderTrackOutputWithTrack:track\n outputSettings:u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e];"
},
{
"title": "How an AVSampleBufferGenerator is created",
"startTimeSeconds": 744,
"endTimeSeconds": 786,
"language": "objectivec",
"code": "u003cspan class=\"syntax-built_in\"u003eAVSampleCursoru003c/spanu003e* cursor = [assetTrack makeSampleCursorAtFirstSampleInDecodeOrder];\n \nu003cspan class=\"syntax-built_in\"u003eAVSampleBufferRequestu003c/spanu003e* request = [[u003cspan class=\"syntax-built_in\"u003eAVSampleBufferRequestu003c/spanu003e alloc] initWithStartCursor:cursor];\n \nrequest.direction = u003cspan class=\"syntax-built_in\"u003eAVSampleBufferRequestDirectionForwardu003c/spanu003e;\nrequest.preferredMinSampleCount = u003cspan class=\"syntax-number\"u003e1u003c/spanu003e;\nrequest.maxSampleCount = u003cspan class=\"syntax-number\"u003e1u003c/spanu003e;\n \nu003cspan class=\"syntax-built_in\"u003eAVSampleBufferGeneratoru003c/spanu003e* generator\n= [[u003cspan class=\"syntax-built_in\"u003eAVSampleBufferGeneratoru003c/spanu003e alloc] initWithAsset:srcAsset timebase:u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e];\n\nu003cspan class=\"syntax-built_in\"u003eBOOLu003c/spanu003e notDone = u003cspan class=\"syntax-literal\"u003eYESu003c/spanu003e;\n \nu003cspan class=\"syntax-keyword\"u003ewhileu003c/spanu003e(notDone)\n{\n u003cspan class=\"syntax-built_in\"u003eCMSampleBufferRefu003c/spanu003e sampleBuffer = [generator createSampleBufferForRequest:request];\n\n u003cspan class=\"syntax-comment\"u003e// do your thing with the sampleBufferu003c/spanu003e\n\n [cursor stepInDecodeOrderByCount:u003cspan class=\"syntax-number\"u003e1u003c/spanu003e];\n}"
},
{
"title": "Pack your sample data into a CMBlockBuffer",
"startTimeSeconds": 820,
"endTimeSeconds": 852,
"language": "objectivec",
"code": "u003cspan class=\"syntax-built_in\"u003eCMBlockBufferCreateWithMemoryBlocku003c/spanu003e(kCFAllocatorDefault, sampleData, u003cspan class=\"syntax-keyword\"u003esizeofu003c/spanu003e(sampleData), \n kCFAllocatorMalloc, u003cspan class=\"syntax-literal\"u003eNULLu003c/spanu003e, u003cspan class=\"syntax-number\"u003e0u003c/spanu003e, u003cspan class=\"syntax-keyword\"u003esizeofu003c/spanu003e(sampleData), u003cspan class=\"syntax-number\"u003e0u003c/spanu003e, \n u0026amp;blockBuffer);\n\nu003cspan class=\"syntax-built_in\"u003eCMVideoFormatDescriptionCreateu003c/spanu003e(kCFAllocatorDefault, kCMVideoCodecType_AppleProRes4444, u003cspan class=\"syntax-number\"u003e1920u003c/spanu003e, \n u003cspan class=\"syntax-number\"u003e1080u003c/spanu003e, extensionsDictionary, u0026amp;formatDescription);\n\nu003cspan class=\"syntax-built_in\"u003eCMSampleTimingInfou003c/spanu003e timingInfo;\n\ntimingInfo.duration = u003cspan class=\"syntax-built_in\"u003eCMTimeMakeu003c/spanu003e(u003cspan class=\"syntax-number\"u003e10u003c/spanu003e, u003cspan class=\"syntax-number\"u003e600u003c/spanu003e);\ntimingInfo.presentationTimeStamp = u003cspan class=\"syntax-built_in\"u003eCMTimeMakeu003c/spanu003e(frameNumber * u003cspan class=\"syntax-number\"u003e10u003c/spanu003e, u003cspan class=\"syntax-number\"u003e600u003c/spanu003e);\n\nu003cspan class=\"syntax-built_in\"u003eCMSampleBufferCreateReadyu003c/spanu003e(kCFAllocatorDefault, blockBuffer, formatDescription, u003cspan class=\"syntax-number\"u003e1u003c/spanu003e, u003cspan class=\"syntax-number\"u003e1u003c/spanu003e, \n u0026amp;timingInfo, u003cspan class=\"syntax-number\"u003e1u003c/spanu003e, u0026amp;sampleSize, u0026amp;sampleBuffer);"
},
{
"title": "VTDecompressionSession Creation",
"startTimeSeconds": 1067,
"endTimeSeconds": 1109,
"language": "objectivec",
"code": "u003cspan class=\"syntax-comment\"u003e// VTDecompressionSession Creationu003c/spanu003e\n\nu003cspan class=\"syntax-built_in\"u003eCMFormatDescriptionRefu003c/spanu003e formatDesc = u003cspan class=\"syntax-built_in\"u003eCMSampleBufferGetFormatDescriptionu003c/spanu003e(sampleBuffer);\n\nu003cspan class=\"syntax-built_in\"u003eCFDictionaryRefu003c/spanu003e pixelBufferAttributes = (__bridge u003cspan class=\"syntax-built_in\"u003eCFDictionaryRefu003c/spanu003e)@{\n (u003cspan class=\"syntax-keyword\"u003eidu003c/spanu003e)kCVPixelBufferPixelFormatTypeKey :\n @(kCVPixelFormatType_4444AYpCbCr16) };\n\nVTDecompressionSessionRef decompressionSession;\n \nOSStatus err = VTDecompressionSessionCreate(kCFAllocatorDefault, \n formatDesc, \n u003cspan class=\"syntax-literal\"u003eNULLu003c/spanu003e,\n pixelBufferAttributes, \n u003cspan class=\"syntax-literal\"u003eNULLu003c/spanu003e, \n u0026amp;decompressionSession);"
},
{
"title": "Running a VTDecompressionSession",
"startTimeSeconds": 1110,
"endTimeSeconds": 1155,
"language": "objectivec",
"code": "u003cspan class=\"syntax-comment\"u003e// Running a VTDecompressionSessionu003c/spanu003e\n\nuint32_t inFlags = kVTDecodeFrame_EnableAsynchronousDecompression;\n\nVTDecompressionOutputHandler outputHandler\n = ^(OSStatus status,\n VTDecodeInfoFlags infoFlags,\n CVImageBufferRef imageBuffer,\n u003cspan class=\"syntax-built_in\"u003eCMTimeu003c/spanu003e presentationTimeStamp,\n u003cspan class=\"syntax-built_in\"u003eCMTimeu003c/spanu003e presentationDurationVTDecodeInfoFlags)\n {\n u003cspan class=\"syntax-comment\"u003e// Handle decoder output in this blocku003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// Status reports any decoder errorsu003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// imageBuffer contains the decoded frame if there were no errorsu003c/spanu003e\n };\n\nVTDecodeInfoFlags outFlags;\n\nOSStatus err = VTDecompressionSessionDecodeFrameWithOutputHandler(decompressionSession,\n sampleBuffer, inFlags, \n u0026amp;outFlags, outputHandler);"
},
{
"title": "CVPixelBuffer to Metal texture: IOSurface",
"startTimeSeconds": 1254,
"endTimeSeconds": 1302,
"language": "objectivec",
"code": "u003cspan class=\"syntax-comment\"u003e// CVPixelBuffer to Metal texture: IOSurfaceu003c/spanu003e\n\nIOSurfaceRef surface = CVPixelBufferGetIOSurface(imageBuffer);\n\nu003cspan class=\"syntax-keyword\"u003eidu003c/spanu003e u0026lt;u003cspan class=\"syntax-built_in\"u003eMTLTextureu003c/spanu003eu0026gt; metalTexture = [metalDevice newTextureWithDescriptor:descriptor\n iosurface:surface \n plane:u003cspan class=\"syntax-number\"u003e0u003c/spanu003e];\n\nu003cspan class=\"syntax-comment\"u003e// Mark the IOSurface as in-use so that it won’t be recycled by the CVPixelBufferPoolu003c/spanu003e\nIOSurfaceIncrementUseCount(surface);\n\nu003cspan class=\"syntax-comment\"u003e// Set up command buffer completion handler to decrement IOSurface use count againu003c/spanu003e\n[cmdBuffer addCompletedHandler:^(u003cspan class=\"syntax-keyword\"u003eidu003c/spanu003eu0026lt;u003cspan class=\"syntax-built_in\"u003eMTLCommandBufferu003c/spanu003eu0026gt; buffer) {\n IOSurfaceDecrementUseCount(surface);\n }];"
},
{
"title": "Create a CVMetalTextureCacheRef",
"startTimeSeconds": 1302,
"endTimeSeconds": 1357,
"language": "objectivec",
"code": "u003cspan class=\"syntax-comment\"u003e// Create a CVMetalTextureCacheRefu003c/spanu003e\n\nCVMetalTextureCacheRef metalTextureCache = u003cspan class=\"syntax-literal\"u003eNULLu003c/spanu003e;\n\nu003cspan class=\"syntax-keyword\"u003eidu003c/spanu003e u0026lt;u003cspan class=\"syntax-built_in\"u003eMTLDeviceu003c/spanu003eu0026gt; metalDevice = u003cspan class=\"syntax-built_in\"u003eMTLCreateSystemDefaultDeviceu003c/spanu003e();\n \nCVMetalTextureCacheCreate(kCFAllocatorDefault, u003cspan class=\"syntax-literal\"u003eNULLu003c/spanu003e, metalDevice, u003cspan class=\"syntax-literal\"u003eNULLu003c/spanu003e, u0026amp;metalTextureCache);\n\nu003cspan class=\"syntax-comment\"u003e// Create a CVMetalTextureRef using metalTextureCache and our pixelBufferu003c/spanu003e\nCVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault,\n metalTextureCache,\n pixelBuffer,\n u003cspan class=\"syntax-literal\"u003eNULLu003c/spanu003e,\n pixelFormat,\n CVPixelBufferGetWidth(pixelBuffer),\n CVPixelBufferGetHeight(pixelBuffer),\n u003cspan class=\"syntax-number\"u003e0u003c/spanu003e,\n u0026amp;cvTexture);\n\nu003cspan class=\"syntax-keyword\"u003eidu003c/spanu003e u0026lt;u003cspan class=\"syntax-built_in\"u003eMTLTextureu003c/spanu003eu0026gt; texture = CVMetalTextureGetTexture(cvTexture);\nu003cspan class=\"syntax-comment\"u003e// Be sure to release the cvTexture object when the Metal command buffer completes!u003c/spanu003e"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10090/6/EA16694F-BEEC-44FF-A129-12336E5390B9/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10090/6/EA16694F-BEEC-44FF-A129-12336E5390B9/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10090/6/EA16694F-BEEC-44FF-A129-12336E5390B9/transcripts/wwdc2020-10090-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10090/6/EA16694F-BEEC-44FF-A129-12336E5390B9/wwdc2020_10090_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10090/6/EA16694F-BEEC-44FF-A129-12336E5390B9/wwdc2020_10090_sd.mp4",
"duration": 1420
},
"related": {
"activities": [
"wwdc2020-10015",
"wwdc2020-10804"
],
"resources": [
1063,
1062,
52
]
}
},
{
"id": "wwdc2020-10093",
"staticContentId": 3505,
"eventContentId": 10093,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10093",
"description": "Help people who use iPad with a Magic Keyboard, mouse, trackpad or other input device get the most out of your app. We’ll show you how to add customizations to the pointer on iPad using pointer interaction APIs, create pointer effects for your buttons and custom views, and change the pointer shape in specific areas of your app to highlight them.\r\n\r\nTo learn more about pointer interactions on iPad and to get the most out of this session, we recommend also watching “Design for the iPadOS pointer” and “Handle trackpad and mouse input.”",
"title": "Build for the iPadOS pointer",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS"
],
"keywords": [
"better ipad",
"cursor",
"dynamic",
"keyboard",
"magic",
"magic keyboard",
"mouse",
"pointer",
"trackpad",
"uikit",
"uitouch"
],
"topicIds": [
3,
22
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "UIButton Pointer Effects",
"startTimeSeconds": 364,
"endTimeSeconds": 410,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Enable the button's built-in pointer interaction.u003c/spanu003e\nmyButton.isPointerInteractionEnabled = u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e\n\nu003cspan class=\"syntax-comment\"u003e// Customize the default interaction effect.u003c/spanu003e\nmyButton.pointerStyleProvider = { button, proposedEffect, proposedShape -u0026gt; u003cspan class=\"syntax-type\"u003eUIPointerStyle?u003c/spanu003e u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n\t\tu003cspan class=\"syntax-comment\"u003e// In this example, we'll switch to using the .lift effect by creating a newu003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// UIPointerEffect with the .lift type using the proposedEffect's preview.u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-type\"u003eUIPointerStyleu003c/spanu003e(effect: .lift(proposedEffect.preview), shape: proposedShape)\n}"
},
{
"title": "Pointer Content Effect",
"startTimeSeconds": 425,
"endTimeSeconds": 480,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Create a UIPointerStyle that applies the .highlight effect. u003c/spanu003e\n\nu003cspan class=\"syntax-comment\"u003e// Outset the view's frame so the pointer shape has some generous padding around the view's contents.u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// Note that this frame must be in the provided UITargetedPreview's container's coordinate space. u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// In the majority of cases (where the preview doesn't have a custom container), this is just the view's superview.u003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e rect = myView.frame.insetBy(dx: -u003cspan class=\"syntax-number\"u003e8.0u003c/spanu003e, dy: -u003cspan class=\"syntax-number\"u003e4.0u003c/spanu003e)\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e preview = u003cspan class=\"syntax-type\"u003eUITargetedPreviewu003c/spanu003e(view: myView)\n\nu003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-type\"u003eUIPointerStyleu003c/spanu003e(effect: .highlight(preview), shape: .roundedRect(rect))"
},
{
"title": "Pointer Shape Customization",
"startTimeSeconds": 482,
"endTimeSeconds": 519,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Create a UIPointerStyle that changes the pointer into a vertical beam. u003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e beamLength = myFont.lineHeight\nu003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-type\"u003eUIPointerStyleu003c/spanu003e(shape: .verticalBeam(length: beamLength), constrainedAxes: .vertical)"
},
{
"title": "UIPointerInteraction Region Entrance Animation",
"startTimeSeconds": 1291,
"endTimeSeconds": 1311,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003epointerInteractionu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e interaction: UIPointerInteraction, \n willEnter region: UIPointerRegion, \n animator: UIPointerInteractionAnimating)u003c/spanu003eu003c/spanu003e {\n\n u003cspan class=\"syntax-comment\"u003e// Fade out separator when entering region.u003c/spanu003e\n animator.addAnimations {\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.separatorView.alpha = u003cspan class=\"syntax-number\"u003e0.0u003c/spanu003e\n }\n}"
},
{
"title": "UIPointerInteraction Region Exit Animation",
"startTimeSeconds": 1311,
"endTimeSeconds": 1316,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003epointerInteractionu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e interaction: UIPointerInteraction, \n willExit region: UIPointerRegion, \n animator: UIPointerInteractionAnimating)u003c/spanu003eu003c/spanu003e {\n\n u003cspan class=\"syntax-comment\"u003e// Fade separator back in when exiting region.u003c/spanu003e\n animator.addAnimations {\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.separatorView.alpha = u003cspan class=\"syntax-number\"u003e1.0u003c/spanu003e\n }\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10093/4/3B8A69F7-49AD-49B5-AFD5-1F1AF706199D/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10093/4/3B8A69F7-49AD-49B5-AFD5-1F1AF706199D/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10093/4/3B8A69F7-49AD-49B5-AFD5-1F1AF706199D/transcripts/wwdc2020-10093-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10093/4/3B8A69F7-49AD-49B5-AFD5-1F1AF706199D/wwdc2020_10093_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10093/4/3B8A69F7-49AD-49B5-AFD5-1F1AF706199D/wwdc2020_10093_sd.mp4",
"duration": 1370
},
"related": {
"activities": [
"wwdc2020-10052",
"wwdc2020-10094",
"wwdc2020-10640",
"wwdc2020-10703",
"wwdc2020-10906"
],
"resources": [
1101,
1100,
892
]
}
},
{
"id": "wwdc2020-10094",
"staticContentId": 3588,
"eventContentId": 10094,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10094",
"description": "Provide a more versatile experience when you optimize your iPad or Mac Catalyst app for indirect input from trackpads and mice. Discover how to make your app responsive to new events from these devices. Learn how to work with pointer movement, enable pointer locking, handle scroll input and trackpad gestures, and accept or reject events on your gesture recognizers. We’ll also show you how to implement advanced features like changing gesture behaviors with keyboard modifiers or pointing device buttons to delight pro users and bring a richer experience to your app.\r\n\r\nTo learn more about pointer-based interactions and to get the most out of this session, we recommend watching “Build for the iPadOS pointer,” “Bring keyboard and mouse gaming to iPad,” and “Support hardware keyboards in your app.”",
"title": "Handle trackpad and mouse input",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS"
],
"keywords": [
"catalyst",
"event",
"magic keyboard",
"mouse",
"trackpad"
],
"topicIds": [
22
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "UIHoverGestureRecognizer",
"startTimeSeconds": 109,
"endTimeSeconds": 145,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e controlsHover = u003cspan class=\"syntax-type\"u003eUIHoverGestureRecognizeru003c/spanu003e(target: u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e, action: #selector(handleHover))\n\nu003cspan class=\"syntax-meta\"u003e@objcu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ehandleHoveru003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e recognizer: UIHoverGestureRecognizer)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eswitchu003c/spanu003e recognizer.state {\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .began:\n u003cspan class=\"syntax-comment\"u003e// Pointer entered our view - show controlsu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.showsPlaybackControls = u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .ended:\n u003cspan class=\"syntax-comment\"u003e// Pointer exited our view - hide controlsu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.showsPlaybackControls = u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003edefaultu003c/spanu003e:\n u003cspan class=\"syntax-keyword\"u003ebreaku003c/spanu003e\n }\n}"
},
{
"title": "prefersPointerLocked",
"startTimeSeconds": 333,
"endTimeSeconds": 353,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eGameViewControlleru003c/spanu003e: u003cspan class=\"syntax-title\"u003eUIViewControlleru003c/spanu003e u003c/spanu003e{\n \n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e shouldLockPointer: u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e = u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e\n \n u003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e prefersPointerLocked: u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.shouldLockPointer\n }\n \n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003edisablePointerLocku003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.shouldLockPointer = u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.setNeedsUpdateOfPrefersPointerLocked()\n }\n}"
},
{
"title": "UIPointerLockState.isLocked",
"startTimeSeconds": 353,
"endTimeSeconds": 390,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e pointerLockState = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.window.windowScene?.pointerLockState {\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.observer = notificationCenter.addObserver(forName: u003cspan class=\"syntax-type\"u003eUIPointerLockStateu003c/spanu003e.didChangeNotification,\n object: pointerLockState,\n queue: u003cspan class=\"syntax-type\"u003eOperationQueueu003c/spanu003e.main) { (note) u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e lockState = note.object u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e? u003cspan class=\"syntax-type\"u003eUIPointerLockStateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e { u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e }\n gameEngine.performExpensiveOperationWhile(lockState.isLocked)\n }\n}"
},
{
"title": "UIPanGestureRecognizer.allowedScrollTypesMask",
"startTimeSeconds": 594,
"endTimeSeconds": 641,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Enable scroll input for touch surface devicesu003c/spanu003e\n \nu003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.drawerPan.allowedScrollTypesMask = [.continuous]\n \n\nu003cspan class=\"syntax-comment\"u003e// Enable scroll input for scroll wheel devices as wellu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.pullToRefreshPan.allowedScrollTypesMask = [.all]"
},
{
"title": "Requiring a 3rd mouse button click",
"startTimeSeconds": 888,
"endTimeSeconds": 907,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.thirdMouseButtonTap.buttonMaskRequired = .button(u003cspan class=\"syntax-number\"u003e3u003c/spanu003e)"
},
{
"title": "Changing response for .alternate keyboard modifier",
"startTimeSeconds": 907,
"endTimeSeconds": 932,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ehandleHoveru003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e recognizer: UIHoverGestureRecognizer)u003c/spanu003eu003c/spanu003e {\n \n u003cspan class=\"syntax-comment\"u003e// Show chapter controls if alt is pressedu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e showChapterControls = recognizer.modifierFlags.u003cspan class=\"syntax-built_in\"u003econtainsu003c/spanu003e(.alternate)\n \n u003cspan class=\"syntax-comment\"u003e// ...u003c/spanu003e\n}"
},
{
"title": "Only handle secondary clicks",
"startTimeSeconds": 998,
"endTimeSeconds": 1056,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eSecondaryClickGestureu003c/spanu003e: u003cspan class=\"syntax-title\"u003eUIGestureRecognizeru003c/spanu003e u003c/spanu003e{\n \n u003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eshouldReceiveu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e event: UIEvent)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Must look at the event’s mask, not the gesture’s u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e event.buttonMask == .secondary\n }\n \n u003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003etouchesBeganu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e touches: Setu0026lt;UITouchu0026gt;, with event: UIEvent)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Touch handling code ...u003c/spanu003e\n }\n}"
},
{
"title": "Only handle secondary clicks or control clicks",
"startTimeSeconds": 1056,
"endTimeSeconds": 1090,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eSecondaryClickGestureu003c/spanu003e: u003cspan class=\"syntax-title\"u003eUIGestureRecognizeru003c/spanu003e u003c/spanu003e{\n \n u003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eshouldReceiveu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e event: UIEvent)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Must look at the event’s properties, not the gesture’su003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e secondaryClick = event.buttonMask == .secondary\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e controlClick = event.buttonMask == .primary u0026amp;u0026amp; event.modifierFlags == .control \n\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e secondaryClick || controlClick\n }\n \n u003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003etouchesBeganu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e touches: Setu0026lt;UITouchu0026gt;, with event: UIEvent)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Touch handling code ...u003c/spanu003e\n }\n}"
},
{
"title": "Only receive hover events with the .alternate modifier pressed",
"startTimeSeconds": 1090,
"endTimeSeconds": 1129,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e ccHover = u003cspan class=\"syntax-type\"u003eUIHoverGestureRecognizeru003c/spanu003e(target: u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e, \n action: #selector(handleClosedCaptionHover))\n\nccHover.delegate = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e\n \nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003egestureRecognizeru003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e gestureRecognizer: UIGestureRecognizer, \n shouldReceive event: UIEvent)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e {\n\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e gestureRecognizer == u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.closedCaptionHover {\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e event.modifierFlags.u003cspan class=\"syntax-built_in\"u003econtainsu003c/spanu003e(.alternate)\n }\n\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10094/3/856B2AFB-E481-490E-A7AC-9446F47C0CFA/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10094/3/856B2AFB-E481-490E-A7AC-9446F47C0CFA/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10094/3/856B2AFB-E481-490E-A7AC-9446F47C0CFA/transcripts/wwdc2020-10094-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10094/3/856B2AFB-E481-490E-A7AC-9446F47C0CFA/wwdc2020_10094_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10094/3/856B2AFB-E481-490E-A7AC-9446F47C0CFA/wwdc2020_10094_sd.mp4",
"duration": 1445
},
"related": {
"activities": [
"wwdc2020-10093",
"wwdc2020-10109",
"wwdc2020-10617",
"wwdc2020-10906",
"wwdc2020-10908",
"wwdc2019-235"
],
"resources": [
1177,
1176
]
}
},
{
"id": "wwdc2020-10095",
"staticContentId": 3764,
"eventContentId": 10095,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10095",
"description": "Help people get the most out of your app with push notifications for important events and updates — and by delivering up-to-date data in the background, so that it is ready when they open your app. Discover how you can use notifications and alert people to timely and relevant information. Learn the differences between alert and background notifications, how to adopt them in your apps, and avoid mistakes by using the right APIs for the job.",
"title": "The Push Notifications primer",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS"
],
"keywords": [
"alert",
"background",
"push"
],
"topicIds": [
18
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Registering for notifications",
"startTimeSeconds": 122,
"endTimeSeconds": 156,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eAppDelegateu003c/spanu003e: u003cspan class=\"syntax-title\"u003eUIResponderu003c/spanu003e, u003cspan class=\"syntax-title\"u003eUIApplicationDelegateu003c/spanu003e, u003cspan class=\"syntax-title\"u003eUNUserNotificationCenterDelegateu003c/spanu003e u003c/spanu003e{\n\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eapplicationu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e application: UIApplication,\n didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: u003cspan class=\"syntax-keyword\"u003eAnyu003c/spanu003e]?)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eUIApplicationu003c/spanu003e.shared.registerForRemoteNotifications()\n u003cspan class=\"syntax-type\"u003eUNUserNotificationCenteru003c/spanu003e.current().delegate = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e\n }"
},
{
"title": "UIApplicationDelegate callbacks",
"startTimeSeconds": 156,
"endTimeSeconds": 181,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eapplicationu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e application: UIApplication,\n didFailToRegisterForRemoteNotificationsWithError error: Error)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// The token is not currently available.u003c/spanu003e\n u003cspan class=\"syntax-built_in\"u003eprintu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Remote notification is unavailable: \\(error.localizedDescription)\"u003c/spanu003e)\n}\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eapplicationu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e application: UIApplication,\n didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Forward the token to your provider, using a custom method.u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.forwardTokenToServer(token: deviceToken)\n}"
},
{
"title": "Forward token to server",
"startTimeSeconds": 185,
"endTimeSeconds": 218,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eforwardTokenToServeru003c/spanu003eu003cspan class=\"syntax-params\"u003e(token: Data)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e tokenComponents = token.u003cspan class=\"syntax-built_in\"u003emapu003c/spanu003e { data u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e(format: u003cspan class=\"syntax-string\"u003e\"%02.2hhx\"u003c/spanu003e, data) }\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e deviceTokenString = tokenComponents.joined()\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e queryItems = [u003cspan class=\"syntax-type\"u003eURLQueryItemu003c/spanu003e(name: u003cspan class=\"syntax-string\"u003e\"deviceToken\"u003c/spanu003e, value: deviceTokenString)]\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e urlComps = u003cspan class=\"syntax-type\"u003eURLComponentsu003c/spanu003e(string: u003cspan class=\"syntax-string\"u003e\"www.example.com/register\"u003c/spanu003e)!\n urlComps.queryItems = queryItems\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e url = urlComps.url u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e\n }\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e task = u003cspan class=\"syntax-type\"u003eURLSessionu003c/spanu003e.shared.dataTask(with: url) { data, response, error u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// Handle datau003c/spanu003e\n }\n\n task.resume()\n}"
},
{
"title": "Request authorization",
"startTimeSeconds": 227,
"endTimeSeconds": 263,
"language": "swift",
"code": "u003cspan class=\"syntax-meta\"u003e@IBActionu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003esubscribeToNotificationsu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e sender: u003cspan class=\"syntax-keyword\"u003eAnyu003c/spanu003e)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e userNotificationCenter = u003cspan class=\"syntax-type\"u003eUNUserNotificationCenteru003c/spanu003e.current()\n userNotificationCenter.requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-built_in\"u003eprintu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Permission granted: \\(granted)\"u003c/spanu003e)\n }\n}"
},
{
"title": "Payload JSON",
"startTimeSeconds": 283,
"endTimeSeconds": 365,
"language": "json",
"code": "{\n u003cspan class=\"syntax-attr\"u003e\"aps\"u003c/spanu003e : {\n u003cspan class=\"syntax-attr\"u003e\"alert\"u003c/spanu003e : {\n u003cspan class=\"syntax-attr\"u003e\"title\"u003c/spanu003e : u003cspan class=\"syntax-string\"u003e\"Check out our new special!\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"body\"u003c/spanu003e : u003cspan class=\"syntax-string\"u003e\"Avocado Bacon Burger on sale\"u003c/spanu003e\n },\n u003cspan class=\"syntax-attr\"u003e\"sound\"u003c/spanu003e : u003cspan class=\"syntax-string\"u003e\"default\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"badge\"u003c/spanu003e : u003cspan class=\"syntax-number\"u003e1u003c/spanu003e,\n },\n u003cspan class=\"syntax-attr\"u003e\"special\"u003c/spanu003e : u003cspan class=\"syntax-string\"u003e\"avocado_bacon_burger\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"price\"u003c/spanu003e : u003cspan class=\"syntax-string\"u003e\"9.99\"u003c/spanu003e\n}"
},
{
"title": "didReceive response",
"startTimeSeconds": 371,
"endTimeSeconds": 429,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003euserNotificationCenteru003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e center: UNUserNotificationCenter,\n didReceive response: UNNotificationResponse,\n withCompletionHandler completionHandler: @escaping u003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e) {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e userInfo = response.notification.request.content.userInfo\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e specialName = userInfo[u003cspan class=\"syntax-string\"u003e\"special\"u003c/spanu003e] u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e? u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e,\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e specialPriceString = userInfo[u003cspan class=\"syntax-string\"u003e\"price\"u003c/spanu003e] u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e? u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e,\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e specialPrice = u003cspan class=\"syntax-type\"u003eFloatu003c/spanu003e(specialPriceString) u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Always call the completion handler when done.u003c/spanu003e\n completionHandler()\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e\n }\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e item = u003cspan class=\"syntax-type\"u003eItemu003c/spanu003e(name: specialName, price: specialPrice)\n\t\taddItemToCart(item)\n \tshowCartViewController()\n completionHandler()\n }"
},
{
"title": "Register for remote notifications (Background)",
"startTimeSeconds": 496,
"endTimeSeconds": 525,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eAppDelegateu003c/spanu003e: u003cspan class=\"syntax-title\"u003eUIResponderu003c/spanu003e, u003cspan class=\"syntax-title\"u003eUIApplicationDelegateu003c/spanu003e u003c/spanu003e{\n\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eapplicationu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e application: UIApplication,\n didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: u003cspan class=\"syntax-keyword\"u003eAnyu003c/spanu003e]?)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eUIApplicationu003c/spanu003e.shared.registerForRemoteNotifications()\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e\n }"
},
{
"title": "Background Notification Payload",
"startTimeSeconds": 545,
"endTimeSeconds": 569,
"language": "json",
"code": "{\n u003cspan class=\"syntax-attr\"u003e\"aps\"u003c/spanu003e : {\n u003cspan class=\"syntax-attr\"u003e\"content-available\"u003c/spanu003e : u003cspan class=\"syntax-number\"u003e1u003c/spanu003e\n },\n u003cspan class=\"syntax-attr\"u003e\"myCustomKey\"u003c/spanu003e : u003cspan class=\"syntax-string\"u003e\"myCustomData\"u003c/spanu003e\n}"
},
{
"title": "didReceiveRemoteNotification",
"startTimeSeconds": 573,
"endTimeSeconds": 657,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eapplicationu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e application: UIApplication,\n didReceiveRemoteNotification userInfo: [AnyHashable : u003cspan class=\"syntax-keyword\"u003eAnyu003c/spanu003e],\n fetchCompletionHandler completionHandler:\n @escaping u003cspan class=\"syntax-params\"u003e(UIBackgroundFetchResult)u003c/spanu003eu003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e) {\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e url = u003cspan class=\"syntax-type\"u003eURLu003c/spanu003e(string: u003cspan class=\"syntax-string\"u003e\"www.example.com/todays-menu\"u003c/spanu003e) u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n completionHandler(.failed)\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e\n }\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e task = u003cspan class=\"syntax-type\"u003eURLSessionu003c/spanu003e.shared.dataTask(with: url) { data, response, error u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e data = data u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n completionHandler(.noData)\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e\n }\n \n updateMenu(withData: data)\n completionHandler(.newData)\n }\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10095/3/ED74BA77-B586-4360-B7A1-ABA71109064A/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10095/3/ED74BA77-B586-4360-B7A1-ABA71109064A/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10095/3/ED74BA77-B586-4360-B7A1-ABA71109064A/transcripts/wwdc2020-10095-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10095/3/ED74BA77-B586-4360-B7A1-ABA71109064A/wwdc2020_10095_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10095/3/ED74BA77-B586-4360-B7A1-ABA71109064A/wwdc2020_10095_sd.mp4",
"duration": 706
},
"related": {
"activities": [
"wwdc2020-10063",
"wwdc2020-10638",
"wwdc2020-10885",
"wwdc2018-806"
],
"resources": [
1285,
1284,
889,
887
]
}
},
{
"id": "wwdc2020-10668",
"staticContentId": 3558,
"eventContentId": 10668,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10668",
"description": "The Nearby Interaction framework streams distance and direction between opted-in Apple devices containing the U1 chip. Discover how this powerful combination of hardware and software allow you to create intuitive spatial interactions based on the relative position of two or more devices. We'll walk you through this session-based API and show you how to deliver entirely new interactive experiences — all with privacy in mind.",
"title": "Meet Nearby Interaction",
"originalPublishingDate": "2020-06-23T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS"
],
"keywords": [
"interactive",
"proximity",
"sharing"
],
"topicIds": [
17
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Basic session setup",
"startTimeSeconds": 361,
"endTimeSeconds": 401,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// A session instance. Store in whichever data structure makes the most sense for your app.u003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e niSession: u003cspan class=\"syntax-type\"u003eNISession?u003c/spanu003e\n\nu003cspan class=\"syntax-comment\"u003e// Instantiate a new session object and set the session's delegate.u003c/spanu003e\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eprepareMySessionu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Verify hardware support.u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-type\"u003eNISessionu003c/spanu003e.isSupported u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n u003cspan class=\"syntax-built_in\"u003eprintu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Nearby Interaction is not available on this device.\"u003c/spanu003e)\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e\n }\n \n u003cspan class=\"syntax-comment\"u003e// Create a new session for each peer.u003c/spanu003e\n niSession = u003cspan class=\"syntax-type\"u003eNISessionu003c/spanu003e()\n\n u003cspan class=\"syntax-comment\"u003e// Set the session’s delegate.u003c/spanu003e\n niSession?.delegate = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e u003cspan class=\"syntax-comment\"u003e// This class of 'self' needs to conform to NISessionDelegate.u003c/spanu003e\n}\n\nu003cspan class=\"syntax-comment\"u003e// Share the encoded discovery token to the peer you intend to interact with.u003c/spanu003e\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003esendDiscoveryTokenToMyPeeru003c/spanu003eu003cspan class=\"syntax-params\"u003e(myPeer: u003cspan class=\"syntax-keyword\"u003eAnyu003c/spanu003e u003cspan class=\"syntax-comment\"u003e/* change to whichever type represents peers in your app */u003c/spanu003e)u003c/spanu003eu003c/spanu003e { \n\tu003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e myToken = niSession?.discoveryToken u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n\t\tu003cspan class=\"syntax-comment\"u003e// The session object is not initialized or has been invalidated.u003c/spanu003e\n\t\tu003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e\n\t}\n\n\tu003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e encodedToken = u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e? u003cspan class=\"syntax-type\"u003eNSKeyedArchiveru003c/spanu003e.archivedData(withRootObject: myToken, requiringSecureCoding: u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e) {\n\t\tu0026lt;# share token using your app's networking layer #u0026gt;\n\t}\n}\n\nu003cspan class=\"syntax-comment\"u003e// Once you receive a token from the peer, create a configuration and run the session.u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// This functions shows how to decode token data that was previously encoded using NSKeyedArchiver.u003c/spanu003e\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003erunMySessionu003c/spanu003eu003cspan class=\"syntax-params\"u003e(peerTokenData: Data)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e peerDiscoveryToken = u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e? u003cspan class=\"syntax-type\"u003eNSKeyedUnarchiveru003c/spanu003e.unarchivedObject(ofClass: u003cspan class=\"syntax-type\"u003eNIDiscoveryTokenu003c/spanu003e.u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e, from: peerTokenData) u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n u003cspan class=\"syntax-built_in\"u003eprintu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Unexpectedly failed to decode discovery token.\"u003c/spanu003e)\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e\n }\n\n u003cspan class=\"syntax-comment\"u003e// Create a session configuration using the discovery token received from the peer.u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e config = u003cspan class=\"syntax-type\"u003eNINearbyPeerConfigurationu003c/spanu003e(peerToken: peerDiscoveryToken)\n\n u003cspan class=\"syntax-comment\"u003e// Run the session with the configuration.u003c/spanu003e\n niSession?.run(config)\n}"
},
{
"title": "Verify hardware support",
"startTimeSeconds": 760,
"endTimeSeconds": 768,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Always verify hardware support.u003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-type\"u003eNISessionu003c/spanu003e.isSupported u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n u003cspan class=\"syntax-built_in\"u003eprintu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Nearby Interaction is not available on this device.\"u003c/spanu003e)\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10668/6/69354ABA-CE3E-4420-A19A-DBF26B4788ED/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10668/6/69354ABA-CE3E-4420-A19A-DBF26B4788ED/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10668/6/69354ABA-CE3E-4420-A19A-DBF26B4788ED/transcripts/wwdc2020-10668-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10668/6/69354ABA-CE3E-4420-A19A-DBF26B4788ED/wwdc2020_10668_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10668/6/69354ABA-CE3E-4420-A19A-DBF26B4788ED/wwdc2020_10668_sd.mp4",
"duration": 932
},
"related": {
"activities": [
"wwdc2020-10660",
"wwdc2020-10676",
"wwdc2020-10760",
"wwdc2020-10849"
],
"resources": [
1137,
1136,
776,
775
]
}
},
{
"id": "wwdc2020-10096",
"staticContentId": 3488,
"eventContentId": 10096,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10096",
"description": "Xcode Playgrounds helps developers explore Swift and framework APIs and provides a scratchpad for rapid experimentation. Learn how Xcode Playgrounds utilizes Xcode's modern build system, provides improved support for resources, and integrates into your projects, frameworks, and Swift packages to improve your documentation and development workflow.",
"title": "Explore Packages and Projects with Xcode Playgrounds",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"keywords": [
"documentation",
"playgrounds",
"resources",
"swift packages",
"xcode",
"xcode playgrounds"
],
"topicIds": [
38,
36
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Playgrounds and resources Demo: Part 1",
"startTimeSeconds": 533,
"endTimeSeconds": 555,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e UIKit\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e image = u003cspan class=\"syntax-type\"u003eUIImageu003c/spanu003e(named: u003cspan class=\"syntax-string\"u003e\"ingredient/orange\"u003c/spanu003e)"
},
{
"title": "Playgrounds and resources Demo: Part 2",
"startTimeSeconds": 618,
"endTimeSeconds": 645,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e CoreML\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e yoloModel = u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e u003cspan class=\"syntax-type\"u003eYOLOv3u003c/spanu003e(configuration: u003cspan class=\"syntax-type\"u003eMLModelConfigurationu003c/spanu003e()).model"
},
{
"title": "Playgrounds and resources Demo: Part 3",
"startTimeSeconds": 654,
"endTimeSeconds": 676,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e UIKit\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e CoreML\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e Vision\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e ingredientNames = [\n u003cspan class=\"syntax-string\"u003e\"banana\"u003c/spanu003e,\n u003cspan class=\"syntax-string\"u003e\"orange\"u003c/spanu003e,\n u003cspan class=\"syntax-string\"u003e\"almond-milk\"u003c/spanu003e,\n]\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e yoloModel = u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e u003cspan class=\"syntax-type\"u003eYOLOv3u003c/spanu003e(configuration: u003cspan class=\"syntax-type\"u003eMLModelConfigurationu003c/spanu003e()).model\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e model = u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e u003cspan class=\"syntax-type\"u003eVNCoreMLModelu003c/spanu003e(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: yoloModel)\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e request = u003cspan class=\"syntax-type\"u003eVNCoreMLRequestu003c/spanu003e(model: model) {u003cspan class=\"syntax-number\"u003e_u003c/spanu003e,u003cspan class=\"syntax-number\"u003e_u003c/spanu003e u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e }"
},
{
"title": "Recognized Object Visualizer",
"startTimeSeconds": 684,
"endTimeSeconds": 700,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e Foundation\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e SwiftUI\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e UIKit\n\nu003cspan class=\"syntax-comment\"u003e// MARK: Modelu003c/spanu003e\n\nu003cspan class=\"syntax-comment\"u003e/// The result of object detection on an image.u003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eObjectDetectionResultu003c/spanu003e : u003cspan class=\"syntax-title\"u003eIdentifiableu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e name: u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e image: u003cspan class=\"syntax-type\"u003eUIImageu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e id: u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e objects: [u003cspan class=\"syntax-type\"u003eRecognizedObjectu003c/spanu003e]\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003einitu003c/spanu003e(name: u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e, image: u003cspan class=\"syntax-type\"u003eUIImageu003c/spanu003e, id: u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e, objects: [u003cspan class=\"syntax-type\"u003eRecognizedObjectu003c/spanu003e]) {\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.id = id\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.name = name\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.image = image\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.objects = objects\n }\n}\n\nu003cspan class=\"syntax-comment\"u003e/// An object recognized by an image classifier.u003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eRecognizedObjectu003c/spanu003e : u003cspan class=\"syntax-title\"u003eIdentifiableu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e id: u003cspan class=\"syntax-type\"u003eIntu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e label: u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e confidence: u003cspan class=\"syntax-type\"u003eDoubleu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e boundingBox: u003cspan class=\"syntax-type\"u003eCGRectu003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003einitu003c/spanu003e(id: u003cspan class=\"syntax-type\"u003eIntu003c/spanu003e, label: u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e, confidence: u003cspan class=\"syntax-type\"u003eDoubleu003c/spanu003e, boundingBox: u003cspan class=\"syntax-type\"u003eCGRectu003c/spanu003e) {\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.id = id\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.label = label\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.confidence = confidence\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.boundingBox = boundingBox\n }\n}\n\nu003cspan class=\"syntax-comment\"u003e// MARK: Viewsu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eRecognizedObjectVisualizeru003c/spanu003e : u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e results: [u003cspan class=\"syntax-type\"u003eObjectDetectionResultu003c/spanu003e]\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e imageSize: u003cspan class=\"syntax-type\"u003eCGFloatu003c/spanu003e = u003cspan class=\"syntax-number\"u003e400u003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003einitu003c/spanu003e(withResults results: [u003cspan class=\"syntax-type\"u003eObjectDetectionResultu003c/spanu003e]) {\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.results = results\n }\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eListu003c/spanu003e(results) { result u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-type\"u003eSpaceru003c/spanu003e()\n\n u003cspan class=\"syntax-type\"u003eVStacku003c/spanu003e(alignment: .center) {\n u003cspan class=\"syntax-type\"u003eRecognizedObjectsViewu003c/spanu003e(\n image: result.image,\n objects: result.objects\n )\n .frame(width: imageSize, height: imageSize)\n\n u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(result.name.capitalized)\n\n u003cspan class=\"syntax-type\"u003eSpaceru003c/spanu003e(minLength: u003cspan class=\"syntax-number\"u003e20u003c/spanu003e)\n }\n\n u003cspan class=\"syntax-type\"u003eSpaceru003c/spanu003e()\n }\n }\n}\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eRecognizedObjectsViewu003c/spanu003e : u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e image: u003cspan class=\"syntax-type\"u003eUIImageu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e objects: [u003cspan class=\"syntax-type\"u003eRecognizedObjectu003c/spanu003e]\n\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eGeometryReaderu003c/spanu003e { geometry u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-type\"u003eImageu003c/spanu003e(uiImage: image)\n .resizable()\n .overlay(\n u003cspan class=\"syntax-type\"u003eZStacku003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eForEachu003c/spanu003e(objects) { object u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-type\"u003eRectangleu003c/spanu003e()\n .stroke(u003cspan class=\"syntax-type\"u003eColoru003c/spanu003e.red)\n .shadow(radius: u003cspan class=\"syntax-number\"u003e2.0u003c/spanu003e)\n .frame(\n width: object.boundingBox.width * geometry.size.width / image.size.width,\n height: object.boundingBox.height * geometry.size.height / image.size.height\n )\n .position(\n x: (object.boundingBox.origin.x + object.boundingBox.size.width / u003cspan class=\"syntax-number\"u003e2.0u003c/spanu003e) * geometry.size.width / image.size.width,\n y: geometry.size.height - (object.boundingBox.origin.y + object.boundingBox.size.height / u003cspan class=\"syntax-number\"u003e2.0u003c/spanu003e) * geometry.size.height / image.size.height\n )\n .overlay(\n u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"\\(object.label.capitalized) (\\(String(format: \"u003c/spanu003e%u003cspan class=\"syntax-number\"u003e0u003c/spanu003e.0fu003cspan class=\"syntax-string\"u003e\", object.confidence * 100.0))%)\"u003c/spanu003e)\n .foregroundColor(u003cspan class=\"syntax-type\"u003eColoru003c/spanu003e.red)\n .position(\n x: (object.boundingBox.origin.x + object.boundingBox.size.width / u003cspan class=\"syntax-number\"u003e2.0u003c/spanu003e) * geometry.size.width / image.size.width,\n y: geometry.size.height - (object.boundingBox.origin.y - u003cspan class=\"syntax-number\"u003e20.0u003c/spanu003e) * geometry.size.height / image.size.height\n )\n )\n }\n }\n )\n }\n }\n}"
},
{
"title": "Playgrounds and resources Demo: Part 4",
"startTimeSeconds": 708,
"endTimeSeconds": 750,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e results = ingredientNames.compactMap { ingredient -u0026gt; u003cspan class=\"syntax-type\"u003eObjectDetectionResult?u003c/spanu003e u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e image = u003cspan class=\"syntax-type\"u003eUIImageu003c/spanu003e(named: u003cspan class=\"syntax-string\"u003e\"ingredient/\\(ingredient)\"u003c/spanu003e) u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e { u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e }\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e handler = u003cspan class=\"syntax-type\"u003eVNImageRequestHandleru003c/spanu003e(cgImage: image.cgImage!)\n u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e? handler.perform([request])\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e observations = request.results u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e! [u003cspan class=\"syntax-type\"u003eVNRecognizedObjectObservationu003c/spanu003e]\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e detectedObjects = observations.enumerated().u003cspan class=\"syntax-built_in\"u003emapu003c/spanu003e { (index, observation) -u0026gt; u003cspan class=\"syntax-type\"u003eRecognizedObjectu003c/spanu003e u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n\n u003cspan class=\"syntax-comment\"u003e// Select only the label with the highest confidence.u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e topLabelObservation = observation.labels[u003cspan class=\"syntax-number\"u003e0u003c/spanu003e]\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e objectBounds = u003cspan class=\"syntax-type\"u003eVNImageRectForNormalizedRectu003c/spanu003e(observation.boundingBox, u003cspan class=\"syntax-type\"u003eIntu003c/spanu003e(image.size.width), u003cspan class=\"syntax-type\"u003eIntu003c/spanu003e(image.size.height))\n\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-type\"u003eRecognizedObjectu003c/spanu003e(id: index, label: topLabelObservation.identifier, confidence: u003cspan class=\"syntax-type\"u003eDoubleu003c/spanu003e(topLabelObservation.confidence), boundingBox: objectBounds)\n }\n\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-type\"u003eObjectDetectionResultu003c/spanu003e(name: ingredient, image: image, id: ingredient, objects: detectedObjects)\n}\n\nresults"
},
{
"title": "Playgrounds and resources Demo: Part 5",
"startTimeSeconds": 753,
"endTimeSeconds": 760,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e PlaygroundSupport\n\nu003cspan class=\"syntax-type\"u003ePlaygroundPageu003c/spanu003e.current.setLiveView(\n u003cspan class=\"syntax-type\"u003eRecognizedObjectVisualizeru003c/spanu003e(withResults: results)\n .frame(width: u003cspan class=\"syntax-number\"u003e500u003c/spanu003e, height: u003cspan class=\"syntax-number\"u003e800u003c/spanu003e)\n)"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10096/4/9D01022D-66DF-4B16-B5B6-B01F57252226/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10096/4/9D01022D-66DF-4B16-B5B6-B01F57252226/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10096/4/9D01022D-66DF-4B16-B5B6-B01F57252226/transcripts/wwdc2020-10096-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10096/4/9D01022D-66DF-4B16-B5B6-B01F57252226/wwdc2020_10096_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10096/3/E26BE90C-7F33-4ADB-9939-505758D60858/wwdc2020_10096_sd.mp4",
"duration": 891
},
"related": {
"activities": [
"wwdc2020-10169",
"wwdc2019-424"
],
"resources": [
1087,
1086,
884
]
}
},
{
"id": "wwdc2020-10603",
"staticContentId": 3415,
"eventContentId": 10603,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10603",
"description": "GPU counters can help you precisely measure GPU utilization to pinpoint bottlenecks and optimize workloads for your Metal apps and games. We’ll walk you through the tools available in the Metal System Trace instrument and Metal Debugger in Xcode 12 to profile your graphics workload, and show you how to use collected data to discover underused and overworked stages of your GPU pipeline. Discover how you can act on that data to improve your app's capabilities.\r\n\r\nTo get the most out of the session, you should understand the tile-based deferred rendering architecture of Apple GPUs and familiarize yourself with our recommended best practices for performance optimization. For a primer, check out “Delivering optimized Metal apps and games” and “Harness Apple GPUs with Metal.”\r\n\r\nOnce you’ve learned how to act on GPU counter data to optimize your Metal apps, see how you can use those skills to \"Bring your Metal app to Apple silicon Macs\" and \"Optimize Metal Performance for Apple silicon Macs\".",
"title": "Optimize Metal apps and games with GPU counters",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS"
],
"topicIds": [
35,
27,
26
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10603/10/54C8A5DF-3A48-4879-8368-234E2AF76D3E/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10603/10/54C8A5DF-3A48-4879-8368-234E2AF76D3E/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10603/9/3AE89720-673B-4B6D-9F4E-BCF0B6088A7A/transcripts/wwdc2020-10603-transcripts.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10603/10/54C8A5DF-3A48-4879-8368-234E2AF76D3E/wwdc2020_10603_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10603/10/54C8A5DF-3A48-4879-8368-234E2AF76D3E/wwdc2020_10603_sd.mp4",
"duration": 1970
},
"related": {
"activities": [
"wwdc2020-10602",
"wwdc2020-10605",
"wwdc2020-10631",
"wwdc2020-10632",
"wwdc2020-10810",
"wwdc2020-10811",
"wwdc2020-10812",
"wwdc2020-10813",
"wwdc2020-10814",
"wwdc2020-10815",
"wwdc2020-10816",
"wwdc2020-10817",
"wwdc2019-606",
"wwdc2018-608"
],
"resources": [
1009,
1008
]
}
},
{
"id": "wwdc2020-10046",
"staticContentId": 3376,
"eventContentId": 10046,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10046",
"description": "When you add complications to a Watch app, people can access glanceable and up to date information directly from their watch face. We’ll show you how to create and build complications from the ground up and introduce you to Multiple Complications. Learn how to construct timelines, use families and templates, and discover best practices on crafting a thorough complication experience.",
"title": "Create complications for Apple Watch",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"watchOS"
],
"keywords": [
"🐋",
"🐳",
"⌚️",
"clockkit",
"watchkit",
"watchos"
],
"topicIds": [
22
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "CLKComplicationDataSource - Required Methods",
"startTimeSeconds": 294,
"endTimeSeconds": 313,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// CLKComplicationDataSource - Requiredu003c/spanu003e\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eComplicationControlleru003c/spanu003e: u003cspan class=\"syntax-title\"u003eNSObjectu003c/spanu003e, u003cspan class=\"syntax-title\"u003eCLKComplicationDataSourceu003c/spanu003e u003c/spanu003e{\n\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003egetCurrentTimelineEntryu003c/spanu003eu003cspan class=\"syntax-params\"u003e(\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e complication: CLKComplication, \n withHandler handler: @escaping u003cspan class=\"syntax-params\"u003e(CLKComplicationTimelineEntry?)u003c/spanu003eu003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e) \n {\n u003cspan class=\"syntax-comment\"u003e// Call the handler with the current timeline entryu003c/spanu003e\n handler(createTimelineEntry(forComplication: complication, date: u003cspan class=\"syntax-type\"u003eDateu003c/spanu003e()))\n }\n}"
},
{
"title": "CLKComplicationDataSource - Timeline Support",
"startTimeSeconds": 316,
"endTimeSeconds": 360,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// CLKComplicationDataSource - Timeline Supportu003c/spanu003e\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eextensionu003c/spanu003e u003cspan class=\"syntax-title\"u003eComplicationControlleru003c/spanu003e u003c/spanu003e{\n\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003egetTimelineEndDateu003c/spanu003eu003cspan class=\"syntax-params\"u003e(\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e complication: CLKComplication, \n withHandler handler: @escaping u003cspan class=\"syntax-params\"u003e(Date?)u003c/spanu003eu003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e) \n {\n handler(timeline(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: complication)?.endDate)\n }\n\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003egetTimelineEntriesu003c/spanu003eu003cspan class=\"syntax-params\"u003e(\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e complication: CLKComplication, \n after date: Date, \n limit: Int, \n withHandler handler: @escaping u003cspan class=\"syntax-params\"u003e([CLKComplicationTimelineEntry]?)u003c/spanu003eu003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e) \n {\n handler(timeline(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: complication)?.entries(after: date, limit: limit))\n }\n}"
},
{
"title": "CLKDateTextProvider initialization",
"startTimeSeconds": 491,
"endTimeSeconds": 501,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e longDate: u003cspan class=\"syntax-type\"u003eDateu003c/spanu003e = u003cspan class=\"syntax-type\"u003eDateComponentsu003c/spanu003e(year: u003cspan class=\"syntax-number\"u003e2020u003c/spanu003e, month: u003cspan class=\"syntax-number\"u003e9u003c/spanu003e, day: u003cspan class=\"syntax-number\"u003e23u003c/spanu003e).date ?? u003cspan class=\"syntax-type\"u003eDateu003c/spanu003e()\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e units: u003cspan class=\"syntax-type\"u003eNSCalendaru003c/spanu003e.u003cspan class=\"syntax-type\"u003eUnitu003c/spanu003e = [.weekday, .month, .day]\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e textProvider = u003cspan class=\"syntax-type\"u003eCLKDateTextProvideru003c/spanu003e(date: longDate, units: units)"
},
{
"title": "CLKRelativeDateTextProvider initialization",
"startTimeSeconds": 529,
"endTimeSeconds": 537,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e timerStart: u003cspan class=\"syntax-type\"u003eDateu003c/spanu003e = …\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e units: u003cspan class=\"syntax-type\"u003eNSCalendaru003c/spanu003e.u003cspan class=\"syntax-type\"u003eUnitu003c/spanu003e = [.hour, .minute, .second]\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e textProvider = u003cspan class=\"syntax-type\"u003eCLKRelativeDateTextProvideru003c/spanu003e(date: timerStart, style: .timer, units: units)"
},
{
"title": "CLKComplicationDataSource - Multiple Complication Support",
"startTimeSeconds": 796,
"endTimeSeconds": 884,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// CLKComplicationDataSource - Multiple Complication Supportu003c/spanu003e\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eextensionu003c/spanu003e u003cspan class=\"syntax-title\"u003eComplicationControlleru003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e descriptors : [u003cspan class=\"syntax-type\"u003eCLKComplicationDescriptoru003c/spanu003e] = []\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e dataDict = u003cspan class=\"syntax-type\"u003eDictionaryu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eAnyHashableu003c/spanu003e, u003cspan class=\"syntax-type\"u003eAnyu003c/spanu003eu0026gt;()\n \n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e station u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e data.stations {\n dataDict = [“nameu003cspan class=\"syntax-string\"u003e\": station.name, “shortName\"u003c/spanu003e: station.shortName]\n descriptors.append(\n u003cspan class=\"syntax-type\"u003eCLKComplicationDescriptoru003c/spanu003e(\n identifier: station.name,\n displayName: station.name,\n supportedFamilies: u003cspan class=\"syntax-type\"u003eCLKComplicationFamilyu003c/spanu003e.allCases,\n userInfo: dataDict))\n }\n \n descriptors.append(\n u003cspan class=\"syntax-type\"u003eCLKComplicationDescriptoru003c/spanu003e(\n identifier: u003cspan class=\"syntax-string\"u003e\"LogSighting\"u003c/spanu003e,\n displayName: u003cspan class=\"syntax-string\"u003e\"Log Sighting\"u003c/spanu003e,\n supportedFamilies: u003cspan class=\"syntax-type\"u003eCLKComplicationFamilyu003c/spanu003e.allCases))\n\n descriptors.append(\n u003cspan class=\"syntax-type\"u003eCLKComplicationDescriptoru003c/spanu003e(\n identifier: u003cspan class=\"syntax-string\"u003e\"SeasonData\"u003c/spanu003e,\n displayName: u003cspan class=\"syntax-string\"u003e\"Season Data\"u003c/spanu003e,\n supportedFamilies: [.graphicRectangular]))\n \n u003cspan class=\"syntax-comment\"u003e// Call the handler with the currently supported complication descriptorsu003c/spanu003e\n handler(descriptors)\n}"
},
{
"title": "CLKComplicationDataSource - Sample Templates",
"startTimeSeconds": 1029,
"endTimeSeconds": 1048,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003egetLocalizableSampleTemplateu003c/spanu003eu003cspan class=\"syntax-params\"u003e(\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e complication: CLKComplication, \n withHandler handler: @escaping u003cspan class=\"syntax-params\"u003e(CLKComplicationTemplate?)u003c/spanu003eu003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e) \n{\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e template = createSampleTemplate(forComplication: complication)\n handler(template)\n}"
},
{
"title": "Whale Watch - Entries",
"startTimeSeconds": 1053,
"endTimeSeconds": 1064,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ecreateTimelineEntryu003c/spanu003eu003cspan class=\"syntax-params\"u003e(\n forComplication complication: CLKComplication, \n date: Date)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eCLKComplicationTimelineEntry?u003c/spanu003e \n{\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e template = createTemplate(forComplication: complication, date: date) u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e\n }\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-type\"u003eCLKComplicationTimelineEntryu003c/spanu003e(date: date, complicationTemplate: template)\n}"
},
{
"title": "Whale Watch - Templates",
"startTimeSeconds": 1064,
"endTimeSeconds": 1159,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ecreateTemplateu003c/spanu003eu003cspan class=\"syntax-params\"u003e(\n forComplication complication: CLKComplication, \n date: Date)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eCLKComplicationTemplate?u003c/spanu003e \n{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e station: u003cspan class=\"syntax-type\"u003eStation?u003c/spanu003e = u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e stationName = complication.userInfo?[u003cspan class=\"syntax-string\"u003e\"name\"u003c/spanu003e] u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e? u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e {\n station = data.stations.first(u003cspan class=\"syntax-keyword\"u003ewhereu003c/spanu003e: { $u003cspan class=\"syntax-number\"u003e0u003c/spanu003e.name == stationName })\n }\n \n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e image = u003cspan class=\"syntax-type\"u003eUIImageu003c/spanu003e(named: u003cspan class=\"syntax-string\"u003e\"Spout-small\"u003c/spanu003e)!\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e spoutFullColorImageProvider = u003cspan class=\"syntax-type\"u003eCLKFullColorImageProvideru003c/spanu003e(fullColorImage: image)\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e logSightingTextProvider = u003cspan class=\"syntax-type\"u003eCLKSimpleTextProvideru003c/spanu003e(\n text: u003cspan class=\"syntax-string\"u003e\"Log Sighting\"u003c/spanu003e, \n shortText: u003cspan class=\"syntax-string\"u003e\"Log\"u003c/spanu003e)\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e defaultTemplate: (u003cspan class=\"syntax-type\"u003eCLKComplicationFamilyu003c/spanu003e) -u0026gt; u003cspan class=\"syntax-type\"u003eCLKComplicationTemplateu003c/spanu003e = { family -u0026gt; u003cspan class=\"syntax-type\"u003eCLKComplicationTemplateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// Return a default complication template for the given familyu003c/spanu003e\n }\n \n u003cspan class=\"syntax-keyword\"u003eswitchu003c/spanu003e (complication.family, complication.identifier) {\n\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e (.graphicRectangular, u003cspan class=\"syntax-string\"u003e\"SeasonData\"u003c/spanu003e):\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-type\"u003eCLKComplicationTemplateGraphicRectangularFullViewu003c/spanu003e(\n u003cspan class=\"syntax-type\"u003eChartViewu003c/spanu003e(\n seriesData: data.last7DaysSightings, \n seriesColor: .turquoise)\n\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e (.graphicCircular, u003cspan class=\"syntax-string\"u003e\"LogSighting\"u003c/spanu003e):\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-type\"u003eCLKComplicationTemplateGraphicCircularStackImageu003c/spanu003e(\n line1ImageProvider: spoutFullColorImageProvider, \n line2TextProvider: logSightingTextProvider)\n\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e (.graphicCircular, u003cspan class=\"syntax-number\"u003e_u003c/spanu003e):\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e station = station u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e { u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e defaultTemplate(.graphicCircular) }\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-type\"u003eCLKComplicationTemplateGraphicCircularViewu003c/spanu003e(\n u003cspan class=\"syntax-type\"u003eSightingTypeViewu003c/spanu003e(station: station))\n \n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e (.graphicCorner, u003cspan class=\"syntax-number\"u003e_u003c/spanu003e):\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e station = station u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e { u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e defaultTemplate(.graphicCorner) }\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-type\"u003eCLKComplicationTemplateGraphicCornerTextImageu003c/spanu003e(\n textProvider: station.timeAndShortLocTextProvider, \n imageProvider: station.whaleActivityFullColorProvider)\n \n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e (.graphicExtraLarge, u003cspan class=\"syntax-number\"u003e_u003c/spanu003e):\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e station = station u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e { u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e defaultTemplate(.graphicExtraLarge) }\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-type\"u003eCLKComplicationTemplateGraphicExtraLargeCircularStackTextu003c/spanu003e(\n line1TextProvider: station.timeAndLocationTextProvider, \n line2TextProvider: station.shortLocationTextProvider)\n\n u003cspan class=\"syntax-keyword\"u003edefaultu003c/spanu003e:\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e defaultTemplate(complication.family)\n }\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10046/4/F29A4217-89E7-4D20-A3CE-3764F44B16D8/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10046/4/F29A4217-89E7-4D20-A3CE-3764F44B16D8/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10046/4/F29A4217-89E7-4D20-A3CE-3764F44B16D8/transcripts/wwdc2020-10046-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10046/4/F29A4217-89E7-4D20-A3CE-3764F44B16D8/wwdc2020_10046_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10046/4/F29A4217-89E7-4D20-A3CE-3764F44B16D8/wwdc2020_10046_sd.mp4",
"duration": 1208
},
"related": {
"activities": [
"wwdc2020-10048",
"wwdc2020-10049",
"wwdc2020-10100",
"wwdc2020-10769",
"wwdc2020-10770",
"wwdc2020-10771",
"wwdc2020-10772"
],
"resources": [
967,
966,
882,
5
]
}
},
{
"id": "wwdc2020-10602",
"staticContentId": 3414,
"eventContentId": 10602,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10602",
"description": "Create visually stunning, high-performance apps and games when you combine the power of Apple GPUs with Metal, the modern foundation for GPU-accelerated graphics on Apple platforms. Discover the architecture and capabilities of the Apple GPU and how Metal harnesses its tile-based deferred rendering (TBDR) architecture to achieve measurable performance gains in apps and games. In this session, we’ll discuss the efficiency of Apple GPUs and show how TBDR applies to an array of modern rendering techniques.\r\n\r\nYou should come to the session with a basic knowledge of Metal and graphics rendering. For a great introduction, check out “Modern Rendering with Metal” to orient yourself.",
"title": "Harness Apple GPUs with Metal",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS"
],
"topicIds": [
25,
27,
26
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10602/7/7EE751FE-713A-4E04-8780-38491023B7B8/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10602/7/7EE751FE-713A-4E04-8780-38491023B7B8/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10602/6/AA82F37F-B500-4A39-86B8-A75D0E101EF7/transcripts/wwdc2020-10602-transcripts.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10602/7/7EE751FE-713A-4E04-8780-38491023B7B8/wwdc2020_10602_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10602/7/7EE751FE-713A-4E04-8780-38491023B7B8/wwdc2020_10602_sd.mp4",
"duration": 1463
},
"related": {
"activities": [
"wwdc2020-10603",
"wwdc2020-10605",
"wwdc2020-10616",
"wwdc2020-10631",
"wwdc2020-10810",
"wwdc2020-10811",
"wwdc2020-10812",
"wwdc2020-10813",
"wwdc2020-10814",
"wwdc2020-10815",
"wwdc2020-10816",
"wwdc2020-10817",
"wwdc2019-606",
"tech-talks-602",
"tech-talks-608",
"tech-talks-10858",
"tech-talks-10859"
],
"resources": [
1007,
1006,
647,
266,
38
]
}
},
{
"id": "wwdc2020-10643",
"staticContentId": 3593,
"eventContentId": 10643,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10643",
"description": "Easily prototype and play around with SwiftUI views when you use them with Swift Playgrounds. We’ll show you how to build a SwiftUI view in a Xcode-compatible playground, and explore tools to help you easily edit and preview your code.\r\n\r\nFor more on Swift Playgrounds, check out our interactive challenge, “Swan's Quest”, and learn to build your own by watching “Create Swift Playgrounds Content for iPad and Mac”.",
"title": "Build a SwiftUI view in Swift Playgrounds",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS"
],
"keywords": [
"ipad",
"playgrounds",
"swift",
"swift playgrounds",
"swiftui"
],
"topicIds": [
36
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Set up for SwiftUI",
"startTimeSeconds": 150,
"endTimeSeconds": 163,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e SwiftUI\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e PlaygroundSupport"
},
{
"title": "Create a simple SwiftUI view",
"startTimeSeconds": 166,
"endTimeSeconds": 186,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eProgressViewu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n \n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Hello, world!\"u003c/spanu003e)\n }\n \n}"
},
{
"title": "Show a SwiftUI live view",
"startTimeSeconds": 192,
"endTimeSeconds": 214,
"language": "swift",
"code": "u003cspan class=\"syntax-type\"u003ePlaygroundPageu003c/spanu003e.current.setLiveView(u003cspan class=\"syntax-type\"u003eProgressViewu003c/spanu003e())"
},
{
"title": "Create a blue circle",
"startTimeSeconds": 241,
"endTimeSeconds": 278,
"language": "swift",
"code": "u003cspan class=\"syntax-type\"u003eCircleu003c/spanu003e()\n\t.stroke(lineWidth: u003cspan class=\"syntax-number\"u003e25u003c/spanu003e)\n\t.foregroundColor(.blue)"
},
{
"title": "Add some padding",
"startTimeSeconds": 306,
"endTimeSeconds": 311,
"language": "swift",
"code": "u003cspan class=\"syntax-type\"u003eProgressViewu003c/spanu003e().padding(u003cspan class=\"syntax-number\"u003e150u003c/spanu003e)"
},
{
"title": "Create an empty ZStack",
"startTimeSeconds": 330,
"endTimeSeconds": 337,
"language": "swift",
"code": "u003cspan class=\"syntax-type\"u003eZStacku003c/spanu003e { }"
},
{
"title": "Add a text view",
"startTimeSeconds": 351,
"endTimeSeconds": 357,
"language": "swift",
"code": "u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"25%\"u003c/spanu003e)"
},
{
"title": "Make a struct public",
"startTimeSeconds": 564,
"endTimeSeconds": 570,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eProgressViewu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{"
},
{
"title": "Make a view's body property public",
"startTimeSeconds": 578,
"endTimeSeconds": 583,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {"
},
{
"title": "Make a view's initializer public",
"startTimeSeconds": 585,
"endTimeSeconds": 590,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003einitu003c/spanu003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e progress: u003cspan class=\"syntax-type\"u003eDoubleu003c/spanu003e = u003cspan class=\"syntax-number\"u003e0.3u003c/spanu003e) {"
},
{
"title": "Create another SwiftUI view",
"startTimeSeconds": 612,
"endTimeSeconds": 621,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003ePreviewu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n \n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// ...u003c/spanu003e\n }\n \n}"
},
{
"title": "Create a VStack of progress views",
"startTimeSeconds": 621,
"endTimeSeconds": 634,
"language": "swift",
"code": "u003cspan class=\"syntax-type\"u003eVStacku003c/spanu003e(spacing: u003cspan class=\"syntax-number\"u003e30u003c/spanu003e) {\n u003cspan class=\"syntax-type\"u003eProgressViewu003c/spanu003e()\n u003cspan class=\"syntax-type\"u003eProgressViewu003c/spanu003e()\n}"
},
{
"title": "Add padding to a view",
"startTimeSeconds": 644,
"endTimeSeconds": 651,
"language": "swift",
"code": ".padding(u003cspan class=\"syntax-number\"u003e100u003c/spanu003e)"
},
{
"title": "Add a system background color to a view",
"startTimeSeconds": 651,
"endTimeSeconds": 672,
"language": "swift",
"code": ".background(u003cspan class=\"syntax-type\"u003eColoru003c/spanu003e(u003cspan class=\"syntax-type\"u003eUIColoru003c/spanu003e.secondarySystemBackground))"
},
{
"title": "Initialize the Preview view",
"startTimeSeconds": 679,
"endTimeSeconds": 683,
"language": "swift",
"code": "u003cspan class=\"syntax-type\"u003ePreviewu003c/spanu003e()"
},
{
"title": "Use an environment modifier to preview dark mode",
"startTimeSeconds": 695,
"endTimeSeconds": 703,
"language": "swift",
"code": ".environment(\\.colorScheme, .dark)"
},
{
"title": "Create a state variable for tracking progress",
"startTimeSeconds": 732,
"endTimeSeconds": 738,
"language": "swift",
"code": "@u003cspan class=\"syntax-type\"u003eStateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e progress = u003cspan class=\"syntax-number\"u003e0.25u003c/spanu003e"
},
{
"title": "Pass the progress to the ProgressView initializer",
"startTimeSeconds": 738,
"endTimeSeconds": 744,
"language": "swift",
"code": "u003cspan class=\"syntax-type\"u003eProgressViewu003c/spanu003e(progress)"
},
{
"title": "Create a method for incrementing progress",
"startTimeSeconds": 752,
"endTimeSeconds": 760,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eincrementu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.progress += u003cspan class=\"syntax-number\"u003e0.25u003c/spanu003e\n}"
},
{
"title": "Add animation to the increment method",
"startTimeSeconds": 760,
"endTimeSeconds": 770,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eincrementu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n withAnimation {\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.progress += u003cspan class=\"syntax-number\"u003e0.25u003c/spanu003e\n }\n}"
},
{
"title": "Create a button",
"startTimeSeconds": 772,
"endTimeSeconds": 781,
"language": "swift",
"code": "u003cspan class=\"syntax-type\"u003eButtonu003c/spanu003e(action: increment)"
},
{
"title": "Add a text label to a button",
"startTimeSeconds": 781,
"endTimeSeconds": 788,
"language": "swift",
"code": "u003cspan class=\"syntax-type\"u003eButtonu003c/spanu003e(action: increment) {\n u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Increment Progress\"u003c/spanu003e)\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10643/4/1EF945FC-088B-4D21-9838-F7CE638EF399/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10643/4/1EF945FC-088B-4D21-9838-F7CE638EF399/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10643/3/25BBA8D0-CBE8-412B-8E9A-4F3DD01D4F18/transcripts/wwdc2020-10643-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10643/4/1EF945FC-088B-4D21-9838-F7CE638EF399/wwdc2020_10643_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10643/4/1EF945FC-088B-4D21-9838-F7CE638EF399/wwdc2020_10643_sd.mp4",
"duration": 854
},
"related": {
"activities": [
"wwdc2020-10654",
"wwdc2020-10681",
"wwdc2020-10682",
"wwdc2020-10683",
"wwdc2020-10684"
],
"resources": [
1181,
1180
]
}
},
{
"id": "wwdc2020-10698",
"staticContentId": 3391,
"eventContentId": 10698,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=dsd023qd",
"description": "",
"title": "Build great app clips",
"articleID": "65145518-31C1-4193-9C85-5629E4BD4CE9",
"articlePermalinkKey": "dsd023qd",
"originalPublishingDate": "2020-06-22T02:00:38-07:00",
"publishingExpiryDate": "2025-06-22T00:32:19-07:00",
"platforms": [
"iOS"
],
"topicIds": [
22
],
"type": "Article",
"images": [
"square",
"wide"
],
"related": {
"activities": [
"wwdc2020-10696",
"wwdc2020-10697",
"wwdc2020-10966"
]
}
},
{
"id": "wwdc2020-10021",
"staticContentId": 3462,
"eventContentId": 10021,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10021",
"description": "Learn how to integrate and load Core Image kernels written in the Metal Shading Language into your application, and discover how you can apply these image filters to create unique effects. Explore how to use Xcode rules and naming conventions for Core Image kernels written in Metal Shading Language. We’ll explain how to best use Core Image APIs effectively and optimally with Metal and the Metal Shading Language.",
"title": "Build Metal-based Core Image kernels with Xcode",
"originalPublishingDate": "2020-06-23T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS"
],
"keywords": [
"coreimage",
"graphics",
"image processing",
"metal",
"performance",
"video",
"xcode"
],
"topicIds": [
38,
35,
31,
30,
27,
24
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Put your kernels in .ci.metal sources",
"startTimeSeconds": 188,
"endTimeSeconds": 272,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// MyKernels.ci.metalu003c/spanu003e\n#include u0026lt;u003cspan class=\"syntax-type\"u003eCoreImageu003c/spanu003e/u003cspan class=\"syntax-type\"u003eCoreImageu003c/spanu003e.hu0026gt; u003cspan class=\"syntax-comment\"u003e// includes CIKernelMetalLib.hu003c/spanu003e\nusing namespace metal;\n\nextern u003cspan class=\"syntax-string\"u003e\"C\"u003c/spanu003e float4 u003cspan class=\"syntax-type\"u003eHDRZebrau003c/spanu003e (coreimage::sample_t s, float time, coreimage::destination dest) \n{\n\tfloat diagLine = dest.coord().x + dest.coord().y;\n\tfloat zebra = fract(diagLine/u003cspan class=\"syntax-number\"u003e20.0u003c/spanu003e + time*u003cspan class=\"syntax-number\"u003e2.0u003c/spanu003e);\n\tu003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e ((zebra u0026gt; u003cspan class=\"syntax-number\"u003e0.5u003c/spanu003e) u0026amp;u0026amp; (s.r u0026gt; u003cspan class=\"syntax-number\"u003e1u003c/spanu003e || s.g u0026gt; u003cspan class=\"syntax-number\"u003e1u003c/spanu003e || s.b u0026gt; u003cspan class=\"syntax-number\"u003e1u003c/spanu003e))\n\t\tu003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e float4(u003cspan class=\"syntax-number\"u003e2.0u003c/spanu003e, u003cspan class=\"syntax-number\"u003e0.0u003c/spanu003e, u003cspan class=\"syntax-number\"u003e0.0u003c/spanu003e, u003cspan class=\"syntax-number\"u003e1.0u003c/spanu003e);\n\tu003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e s;\n}"
},
{
"title": "Loading your kernel and applying it to create a new image",
"startTimeSeconds": 298,
"endTimeSeconds": 333,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eHDRZebraFilteru003c/spanu003e: u003cspan class=\"syntax-title\"u003eCIFilteru003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e inputImage: u003cspan class=\"syntax-type\"u003eCIImage?u003c/spanu003e\n\tu003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e inputTime: u003cspan class=\"syntax-type\"u003eFloatu003c/spanu003e = u003cspan class=\"syntax-number\"u003e0.0u003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003estaticu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e kernel: u003cspan class=\"syntax-type\"u003eCIColorKernelu003c/spanu003e = { () -u0026gt; u003cspan class=\"syntax-type\"u003eCIColorKernelu003c/spanu003e u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e \n\t u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e url = u003cspan class=\"syntax-type\"u003eBundleu003c/spanu003e.main.url(forResource: u003cspan class=\"syntax-string\"u003e\"MyKernels\"u003c/spanu003e, \n withExtension: u003cspan class=\"syntax-string\"u003e\"ci.metallib\"u003c/spanu003e)!\n\t\tu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e data = u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e! u003cspan class=\"syntax-type\"u003eDatau003c/spanu003e(contentsOf: url)\n\t\tu003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e! u003cspan class=\"syntax-type\"u003eCIColorKernelu003c/spanu003e(functionName: u003cspan class=\"syntax-string\"u003e\"HDRzebra\"u003c/spanu003e, u2028 fromMetalLibraryData: data)\n\t}()\n\n \tu003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e outputImage : u003cspan class=\"syntax-type\"u003eCIImage?u003c/spanu003e {\n\t\tu003cspan class=\"syntax-keyword\"u003egetu003c/spanu003e {\n\t\t\tu003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e input = inputImage u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e}\n\t\t\tu003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-type\"u003eHDRZebraFilteru003c/spanu003e.kernel.apply(extent: input.extent, \n\t\t\t\t\t\t\t\t\t\t\t arguments: [input, inputTime])\n\t\t}\n\t}\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10021/7/91A7268C-8211-46D3-B08E-9F554CE138A1/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10021/7/91A7268C-8211-46D3-B08E-9F554CE138A1/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10021/7/91A7268C-8211-46D3-B08E-9F554CE138A1/transcripts/wwdc2020-10021-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10021/7/91A7268C-8211-46D3-B08E-9F554CE138A1/wwdc2020_10021_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10021/7/91A7268C-8211-46D3-B08E-9F554CE138A1/wwdc2020_10021_sd.mp4",
"duration": 372
},
"related": {
"activities": [
"wwdc2020-10008",
"wwdc2020-10014",
"wwdc2020-10089",
"wwdc2020-10723"
],
"resources": [
1061,
1060,
32
]
}
},
{
"id": "wwdc2020-20003",
"staticContentId": 4573,
"eventContentId": 20003,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=losqp2ev",
"description": "",
"title": "Wednesday",
"articleID": "E8362352-44CD-4A1E-B393-1E5D30A54332",
"articlePermalinkKey": "losqp2ev",
"originalPublishingDate": "2020-06-24T08:55:45-07:00",
"publishingExpiryDate": "2025-06-24T09:22:11-07:00",
"topicIds": [
],
"type": "Article",
"images": [
"square",
"wide"
]
},
{
"id": "wwdc2020-10745",
"staticContentId": 3485,
"eventContentId": 10745,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=4ii0mffp",
"description": "",
"title": "SwiftUI Previews in Xcode 12",
"articleID": "CDFE9449-5F1D-4702-8D70-61EF55A8B66F",
"articlePermalinkKey": "4ii0mffp",
"originalPublishingDate": "2020-06-22T01:00:45-07:00",
"publishingExpiryDate": "2025-06-22T00:42:40-07:00",
"topicIds": [
],
"type": "Article",
"images": [
"square",
"wide"
]
},
{
"id": "wwdc2020-10119",
"staticContentId": 3359,
"eventContentId": 10119,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10119",
"description": "Explore the world of declarative-style programming: Discover how to build a fully-functioning SwiftUI app from scratch as we explain the benefits of writing declarative code and how SwiftUI and Xcode can combine forces to help you build great apps, faster.",
"title": "Introduction to SwiftUI",
"originalPublishingDate": "2020-06-23T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"keywords": [
"animation",
".aspectratio",
"canvas",
"compositional ui",
"corner radius",
"dark mode",
"declarative syntax",
"declarative ui",
"dependency management",
"derived value",
"horizontal stack",
"hstack",
"inspector",
"leading alignment",
"library",
"live mode",
"localization",
"model",
"modifiers",
"multiplatform app template",
"navigationview",
"padding",
"preview on device",
"previews",
".resizable",
"resume updating preview",
"sfsymbol",
"source of truth",
"spacer",
"state variable",
"swift",
"text",
"vertical stack",
"view",
"views",
"vstack",
"xcode library",
"zoom state"
],
"topicIds": [
38,
36,
22
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Views are lightweight",
"startTimeSeconds": 1038,
"endTimeSeconds": 1085,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eSandwichDetailu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e sandwich: u003cspan class=\"syntax-type\"u003eSandwichu003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eImageu003c/spanu003e(sandwich.imageName)\n .resizable()\n .aspectRatio(contentMode: .fit)\n }\n}"
},
{
"title": "Views are composed",
"startTimeSeconds": 1110,
"endTimeSeconds": 1163,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eSandwichDetailu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e sandwich: u003cspan class=\"syntax-type\"u003eSandwichu003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eImageu003c/spanu003e(sandwich.imageName)\n .resizable()\n .aspectRatio(contentMode: .fit)\n }\n}"
},
{
"title": "View are dynamic",
"startTimeSeconds": 1192,
"endTimeSeconds": 1260,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eSandwichDetailu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e sandwich: u003cspan class=\"syntax-type\"u003eSandwichu003c/spanu003e\n @u003cspan class=\"syntax-type\"u003eStateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eprivateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e zoomed = u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eImageu003c/spanu003e(sandwich.imageName)\n .resizable()\n .aspectRatio(contentMode: zoomed ? .fill : .fit)\n .onTapGesture { zoomed.toggle() }\n }\n}"
},
{
"title": "Where is truth?",
"startTimeSeconds": 1300,
"endTimeSeconds": 1360,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eSandwichDetailu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e sandwich: u003cspan class=\"syntax-type\"u003eSandwichu003c/spanu003e\n @u003cspan class=\"syntax-type\"u003eStateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eprivateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e zoomed = u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eImageu003c/spanu003e(sandwich.imageName)\n .resizable()\n .aspectRatio(contentMode: zoomed ? .fill : .fit)\n .onTapGesture { zoomed.toggle() }\n }\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10119/7/C3E13536-E82C-4A52-B2E6-1D04D0991648/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10119/7/C3E13536-E82C-4A52-B2E6-1D04D0991648/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10119/7/C3E13536-E82C-4A52-B2E6-1D04D0991648/transcripts/wwdc2020-10119-transcripts.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10119/7/C3E13536-E82C-4A52-B2E6-1D04D0991648/wwdc2020_10119_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10119/7/C3E13536-E82C-4A52-B2E6-1D04D0991648/wwdc2020_10119_sd.mp4",
"duration": 3278
},
"related": {
"activities": [
"wwdc2020-10037",
"wwdc2020-10040",
"wwdc2020-10041",
"wwdc2020-10638",
"wwdc2019-237"
],
"resources": [
955,
954,
571
]
}
},
{
"id": "wwdc2020-10971",
"staticContentId": 4443,
"eventContentId": 10971,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10971",
"description": "Ever wondered which is more fun — filming in a hot tub or filming in a VR suit? \r\nThe cast and creators of the Apple TV+ hit show Mythic Quest: Raven’s Banquet answer questions from the Apple developer community. Join Rob McElhenney (executive producer/co-creator and Ian Grimm), Charlotte Nicdao (Poppy), Imani Hakim (Dana), Danny Pudi (Brad), and Megan Ganz (executive producer/co-creator) as they review one of their favorite scenes and answer submitted questions.",
"title": "Submit your questions for the cast and creators of Mythic Quest: Raven’s Banquet",
"originalPublishingDate": "2020-06-22T12:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"keywords": [
"apple tv+",
"charlotte nicdao",
"danny pudi",
"imani khan",
"megan ganz",
"mq",
"mythic",
"mythic quest",
"quarantine",
"quest",
"raven",
"raven's banquet",
"rob mcelhenney"
],
"topicIds": [
1
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10971/1/FF509CCC-FCE3-49F2-9BD8-7C0F1B1D9CA2/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10971/1/FF509CCC-FCE3-49F2-9BD8-7C0F1B1D9CA2/master.m3u8",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10971/1/FF509CCC-FCE3-49F2-9BD8-7C0F1B1D9CA2/wwdc2020_10971_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10971/1/FF509CCC-FCE3-49F2-9BD8-7C0F1B1D9CA2/wwdc2020_10971_sd.mp4",
"duration": 42
},
"related": {
"activities": [
"wwdc2020-10969"
],
"resources": [
865
]
}
},
{
"id": "wwdc2020-10182",
"staticContentId": 3869,
"eventContentId": 10182,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10182",
"description": "HealthKit is an essential framework that integrates first- and third-party health and fitness data to help people manage their personal health information. Learn about HealthKit’s latest updates, which provide read access to electrocardiograms on Apple Watch and log and track over a dozen new symptoms and their severity. We’ll also go through the latest mobility data types like walking speed and step length to help people monitor and understand their mobility over time.",
"title": "What's new in HealthKit",
"originalPublishingDate": "2020-06-23T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"watchOS"
],
"keywords": [
"ecg",
"fitness",
"health",
"heart",
"heart rate",
"nutrition"
],
"topicIds": [
14
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10182/4/96BB3F0A-784E-4154-A542-2F681FB93E30/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10182/4/96BB3F0A-784E-4154-A542-2F681FB93E30/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10182/4/96BB3F0A-784E-4154-A542-2F681FB93E30/transcripts/wwdc2020-10182-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10182/4/96BB3F0A-784E-4154-A542-2F681FB93E30/wwdc2020_10182_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10182/4/96BB3F0A-784E-4154-A542-2F681FB93E30/wwdc2020_10182_sd.mp4",
"duration": 369
},
"related": {
"activities": [
"wwdc2020-10184",
"wwdc2020-10656",
"wwdc2020-10664",
"wwdc2020-10669",
"wwdc2020-10755",
"wwdc2020-10843"
],
"resources": [
1327,
1326
]
}
},
{
"id": "wwdc2020-10027",
"staticContentId": 3809,
"eventContentId": 10027,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10027",
"description": "Discover new techniques for configuring collection view and table view cells to quickly build dynamic interfaces in your app. Explore configuration types you can use to easily populate cells with content and apply common styles. Take advantage of powerful APIs to customize the appearance of cells for different states. Find out about patterns and best practices that simplify your code, eliminate bugs, and improve performance.",
"title": "Modern cell configuration",
"originalPublishingDate": "2020-06-23T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS"
],
"keywords": [
"collectionview",
"tableview",
"uicollectionview",
"uitableview"
],
"topicIds": [
22
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Configuring a UITableViewCell",
"startTimeSeconds": 91,
"endTimeSeconds": 110,
"language": "swift",
"code": "cell.imageView?.image = u003cspan class=\"syntax-type\"u003eUIImageu003c/spanu003e(systemName: u003cspan class=\"syntax-string\"u003e\"star\"u003c/spanu003e)\ncell.textLabel?.text = u003cspan class=\"syntax-string\"u003e\"Hello WWDC!\"u003c/spanu003e"
},
{
"title": "Configuring a UITableViewCell Using a Content Configuration",
"startTimeSeconds": 119,
"endTimeSeconds": 198,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e content = cell.defaultContentConfiguration()\n\ncontent.image = u003cspan class=\"syntax-type\"u003eUIImageu003c/spanu003e(systemName: u003cspan class=\"syntax-string\"u003e\"star\"u003c/spanu003e)\ncontent.text = u003cspan class=\"syntax-string\"u003e\"Hello WWDC!\"u003c/spanu003e\n\ncell.contentConfiguration = content"
},
{
"title": "Updating Configurations",
"startTimeSeconds": 790,
"endTimeSeconds": 824,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e updatedConfiguration = configuration.updated(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: state)"
},
{
"title": "Customizing Appearance for Different States",
"startTimeSeconds": 993,
"endTimeSeconds": 1058,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eupdateConfigurationu003c/spanu003eu003cspan class=\"syntax-params\"u003e(using state: UICellConfigurationState)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e content = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.defaultContentConfiguration().updated(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: state)\n \n content.image = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.item.icon\n content.text = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.item.title\n \n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e state.isHighlighted || state.isSelected {\n content.imageProperties.tintColor = .white\n content.textProperties.color = .white\n }\n \n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.contentConfiguration = content\n}"
},
{
"title": "Default Configurations",
"startTimeSeconds": 1185,
"endTimeSeconds": 1214,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e background = u003cspan class=\"syntax-type\"u003eUIBackgroundConfigurationu003c/spanu003e.listSidebarCell()\n\nu003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e content = u003cspan class=\"syntax-type\"u003eUIListContentConfigurationu003c/spanu003e.sidebarCell()"
},
{
"title": "Creating a List Content View",
"startTimeSeconds": 1583,
"endTimeSeconds": 1620,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e content = u003cspan class=\"syntax-type\"u003eUIListContentConfigurationu003c/spanu003e.cell()\n\nu003cspan class=\"syntax-comment\"u003e// Set up the content configuration as desired...u003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e contentView = u003cspan class=\"syntax-type\"u003eUIListContentViewu003c/spanu003e(configuration: content)"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10027/2/8BF22D86-7C86-4813-980B-183CC5B693DE/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10027/2/8BF22D86-7C86-4813-980B-183CC5B693DE/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10027/2/8BF22D86-7C86-4813-980B-183CC5B693DE/transcripts/wwdc2020-10027-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10027/2/8BF22D86-7C86-4813-980B-183CC5B693DE/wwdc2020_10027_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10027/2/8BF22D86-7C86-4813-980B-183CC5B693DE/wwdc2020_10027_sd.mp4",
"duration": 1780
},
"related": {
"activities": [
"wwdc2020-10026",
"wwdc2020-10045",
"wwdc2020-10097",
"wwdc2020-10105",
"wwdc2020-10907"
],
"resources": [
1311,
1310,
530
]
}
},
{
"id": "wwdc2020-10159",
"staticContentId": 3666,
"eventContentId": 10159,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10159",
"description": "System Extensions improve the reliability and security of macOS. Learn about the modern replacement for Kernel Authorization KPIs and discover tips for making a great security product with the Endpoint Security framework.",
"title": "Build an Endpoint Security app",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"macOS"
],
"keywords": [
"kauth",
"kernel",
"security"
],
"topicIds": [
67,
19
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10159/7/8B7397DB-B3A9-48C8-A9B7-2F8512EFDB29/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10159/7/8B7397DB-B3A9-48C8-A9B7-2F8512EFDB29/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10159/7/8B7397DB-B3A9-48C8-A9B7-2F8512EFDB29/transcripts/wwdc2020-10159-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10159/7/8B7397DB-B3A9-48C8-A9B7-2F8512EFDB29/wwdc2020_10159_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10159/7/8B7397DB-B3A9-48C8-A9B7-2F8512EFDB29/wwdc2020_10159_sd.mp4",
"duration": 2495
},
"related": {
"activities": [
"wwdc2020-10211",
"wwdc2020-10638",
"wwdc2020-10676",
"wwdc2020-10778",
"wwdc2020-10779",
"wwdc2019-702"
],
"resources": [
1225,
1224,
910,
579
]
}
},
{
"id": "wwdc2020-10038",
"staticContentId": 4536,
"eventContentId": 10038,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=g58zvm7o",
"description": "",
"title": "Optimize your Shortcuts",
"articleID": "BAB9C731-271D-4858-B97D-30D81267C7A9",
"articlePermalinkKey": "g58zvm7o",
"originalPublishingDate": "2020-06-22T02:26:00-07:00",
"publishingExpiryDate": "2025-06-22T04:35:55-07:00",
"topicIds": [
],
"type": "Article",
"images": [
"square",
"wide"
]
},
{
"id": "wwdc2020-10231",
"staticContentId": 3708,
"eventContentId": 10231,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10231",
"description": "Blocking Playlist Reload is a required component of Low-Latency HLS that improves segment discovery time in live streams and addresses the common problem of stale playlists when delivering through an HTTP cache. Learn how to use Blocking Playlist Reload to reduce streaming latency and improve CDN performance for both low-latency and regular live HLS streams.",
"title": "Reduce latency with HLS Blocking Playlist Reload",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"topicIds": [
31,
28
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10231/3/2F8E5799-0623-407E-A395-57E1DE70D4D0/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10231/3/2F8E5799-0623-407E-A395-57E1DE70D4D0/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10231/2/5D88EA3B-85D1-4061-AD0C-B03C854C6250/transcripts/wwdc2020-10231-transcripts.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10231/3/2F8E5799-0623-407E-A395-57E1DE70D4D0/wwdc2020_10231_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10231/3/2F8E5799-0623-407E-A395-57E1DE70D4D0/wwdc2020_10231_sd.mp4",
"duration": 520
},
"related": {
"activities": [
"wwdc2020-10225",
"wwdc2020-10228",
"wwdc2020-10229",
"wwdc2020-10230",
"wwdc2020-10232",
"wwdc2020-10847",
"wwdc2020-10851"
],
"resources": [
1259,
1258
]
}
},
{
"id": "wwdc2020-10209",
"staticContentId": 3371,
"eventContentId": 10209,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10209",
"description": "Core NFC helps you scan and write to NFC tags in your apps, helping people get more from objects like parking meters, scooter rentals, car charging stations, and more. Learn about Core NFC’s support for the ISO15693 protocol and new tag capabilities, and find out more about syntax improvements for Swift.",
"title": "What's new in Core NFC",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS"
],
"keywords": [
"nfc"
],
"topicIds": [
22
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "sendCommand",
"startTimeSeconds": 204,
"endTimeSeconds": 223,
"language": "swift",
"code": "detectedTag.sendCommand(apdu: apdu) { (result: u003cspan class=\"syntax-type\"u003eResultu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eNFCISO7816ResponseAPDUu003c/spanu003e, u003cspan class=\"syntax-type\"u003eErroru003c/spanu003eu0026gt;) u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eswitchu003c/spanu003e result {\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .success(u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e responseAPDU):\n u003cspan class=\"syntax-comment\"u003e/// Handle NFCISO7816ResponseAPDU object.u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .failure(u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e error):\n u003cspan class=\"syntax-comment\"u003e/// Handle Error object.u003c/spanu003e\n }\n}"
},
{
"title": "sendMiFareCommand",
"startTimeSeconds": 246,
"endTimeSeconds": 257,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// You need to zero-pad the data to fill the block sizeu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e blockData.u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e u0026lt; blockSize {\n blockData += u003cspan class=\"syntax-type\"u003eDatau003c/spanu003e(u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e: blockSize - blockData.u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e)\n}\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e writeCommand = u003cspan class=\"syntax-type\"u003eDatau003c/spanu003e([writeBlockCommand, offset]) + blockData\ntag.sendMiFareCommand(commandPacket: writeCommand) { (response: u003cspan class=\"syntax-type\"u003eResultu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eDatau003c/spanu003e, u003cspan class=\"syntax-type\"u003eErroru003c/spanu003eu0026gt;) u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eswitchu003c/spanu003e (response) {\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .success(u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e responseData):\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e responseData[u003cspan class=\"syntax-number\"u003e0u003c/spanu003e] != successCode {\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.readerSession?.invalidate(errorMessage: u003cspan class=\"syntax-string\"u003e\"Write tag error. Please try again.\"u003c/spanu003e)\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e\n }\n \n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e newSize = data.u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e - blockSize\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e newSize u0026gt; u003cspan class=\"syntax-number\"u003e0u003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.write(data.suffix(newSize), to: tag, offset: (offset + u003cspan class=\"syntax-number\"u003e1u003c/spanu003e))\n } u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.readerSession?.invalidate()\n }\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .failure(u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e error):\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e message = u003cspan class=\"syntax-string\"u003e\"Write tag error: \\(error.localizedDescription). Please try again.\"u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.readerSession?.invalidate(errorMessage: message)\n }\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10209/4/A0EF8CFC-5168-44DA-9F88-3ECE05F82ACE/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10209/4/A0EF8CFC-5168-44DA-9F88-3ECE05F82ACE/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10209/3/E34B1C8D-964F-4E10-BC7F-18F52CF7A2FF/transcripts/wwdc2020-10209-transcripts.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10209/4/A0EF8CFC-5168-44DA-9F88-3ECE05F82ACE/wwdc2020_10209_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10209/4/A0EF8CFC-5168-44DA-9F88-3ECE05F82ACE/wwdc2020_10209_sd.mp4",
"duration": 351
},
"related": {
"activities": [
"wwdc2020-10892",
"wwdc2019-715"
],
"resources": [
961,
960,
535
]
}
},
{
"id": "wwdc2020-10664",
"staticContentId": 3406,
"eventContentId": 10664,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10664",
"description": "HealthKit helps you build world-class health and fitness apps by centralizing health data from third-party apps, iPhone, Apple Watch, and external health devices. Discover how you can manage authorization and privacy around Health data, read and write data to the shared Health Store, and use HealthKit’s built-in queries to fetch data and calculate statistics for that data.",
"title": "Getting started with HealthKit",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"watchOS"
],
"keywords": [
"diagnostic",
"permission requests",
"permissions"
],
"topicIds": [
14
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10664/3/A57EEE02-9009-45A1-B08B-797CE7A6F83B/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10664/3/A57EEE02-9009-45A1-B08B-797CE7A6F83B/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10664/2/FA38CC5F-747A-4607-A053-AD073483581F/transcripts/wwdc2020-10664-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10664/3/A57EEE02-9009-45A1-B08B-797CE7A6F83B/wwdc2020_10664_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10664/3/A57EEE02-9009-45A1-B08B-797CE7A6F83B/wwdc2020_10664_sd.mp4",
"duration": 1932
},
"related": {
"activities": [
"wwdc2020-10151",
"wwdc2020-10182",
"wwdc2020-10184",
"wwdc2020-10656",
"wwdc2020-10694",
"wwdc2020-10755",
"wwdc2020-10843"
],
"resources": [
991,
990,
897,
422,
87
]
}
},
{
"id": "wwdc2020-10232",
"staticContentId": 3709,
"eventContentId": 10232,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10232",
"description": "Find out how to integrate advertising into your Low-Latency HLS streams through server-side ad insertion. We'll show you how to segment your ad content, and examine how ad insertion works with LL-HLS features such as Blocking Playlist Reload and Blocking Preload Hints.\r\n\r\nFor more information about Blocking Playlist Reload and Preload Hinting, watch \"Reduce Latency with HLS Blocking Playlist Reload\" and \"Discover HLS Blocking Preload Hints.\"",
"title": "Adapt ad insertion to Low-Latency HLS",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"topicIds": [
31,
28
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10232/4/D14B77B1-D4C9-4BD0-A395-843696269639/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10232/4/D14B77B1-D4C9-4BD0-A395-843696269639/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10232/3/C27BB5C5-359F-43E8-B2EF-58DF1634503C/transcripts/wwdc2020-10232-transcripts.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10232/4/D14B77B1-D4C9-4BD0-A395-843696269639/wwdc2020_10232_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10232/4/D14B77B1-D4C9-4BD0-A395-843696269639/wwdc2020_10232_sd.mp4",
"duration": 579
},
"related": {
"activities": [
"wwdc2020-10229",
"wwdc2020-10230",
"wwdc2020-10231",
"wwdc2020-10847",
"wwdc2020-10851"
],
"resources": [
1261,
1260
]
}
},
{
"id": "wwdc2020-10969",
"staticContentId": 4441,
"eventContentId": 10969,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10969",
"description": "Ever wondered which is more fun — filming in a hot tub or filming in a VR suit?\r\nThe cast and creators of the Apple TV+ hit show Mythic Quest: Raven’s Banquet answer questions from the Apple developer community. Join Rob McElhenney (executive producer/co-creator and Ian Grimm), Charlotte Nicdao (Poppy), Imani Hakim (Dana), Danny Pudi (Brad), and Megan Ganz (executive producer/co-creator) as they review one of their favorite scenes and answer submitted questions.\r\n\r\nNote: Contains adult language. Mythic Quest: Raven’s Banquet is rated TV-MA.",
"title": "A conversation with the cast and creators of Mythic Quest: Raven’s Banquet",
"originalPublishingDate": "2020-06-25T17:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"keywords": [
"apple tv+",
"charlotte nicdao",
"danny pudi",
"imani khan",
"mq",
"mythic",
"mythic quest",
"quest",
"raven",
"raven's banquet",
"rob mcelhenney"
],
"topicIds": [
1
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10969/4/8C4E91EB-B1EC-45EA-8964-ADA23A5C50A0/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10969/4/8C4E91EB-B1EC-45EA-8964-ADA23A5C50A0/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10969/4/8C4E91EB-B1EC-45EA-8964-ADA23A5C50A0/transcripts/wwdc2020-10969-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10969/4/8C4E91EB-B1EC-45EA-8964-ADA23A5C50A0/wwdc2020_10969_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10969/4/8C4E91EB-B1EC-45EA-8964-ADA23A5C50A0/wwdc2020_10969_sd.mp4",
"duration": 1560
},
"related": {
"activities": [
"wwdc2020-10971"
]
}
},
{
"id": "wwdc2020-10188",
"staticContentId": 3410,
"eventContentId": 10188,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10188",
"description": "WKWebView is the best way to present rich, interactive web content right within your app. Explore new APIs that help you convert apps using WebViews or UIWebViews while adding entirely new capabilities. Learn about better ways to handle JavaScript, fine tune the rendering process, export web content, and more.",
"title": "Discover WKWebView enhancements",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS"
],
"keywords": [
"allowscontentjavascript",
"app-bound domains",
"bitmap",
"browser",
"callasyncjavascript",
"console",
"createpdf",
"createwebarchivedata",
"css",
"evaluatejavascript",
"findstring",
"html",
"intelligent tracking prevention",
"itp",
"javascript",
"javascriptenabled",
"jscontext",
"mediastyle",
"mediatype",
"messagehandlers",
"pagezoom",
"postmessage",
"printoperationwithprintinfo",
"promise",
"safari technology preview",
"safari view controller",
"sfsafariviewcontroller",
"share as pdf",
"snapshot",
"takesnapshot",
"uiwebview",
"web archive",
"web content",
"web inspector",
"webkit",
"webpage",
"website",
"webview",
"web views",
"wkappbounddomains",
"wkcontentworld",
"wkpreferences",
"wkscriptmessagehandler",
"wkwebpagepreferences"
],
"topicIds": [
20
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10188/3/6E5129F2-8309-4EDE-BEEA-B2B32A39A5FB/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10188/3/6E5129F2-8309-4EDE-BEEA-B2B32A39A5FB/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10188/3/6E5129F2-8309-4EDE-BEEA-B2B32A39A5FB/transcripts/wwdc2020-10188-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10188/3/6E5129F2-8309-4EDE-BEEA-B2B32A39A5FB/wwdc2020_10188_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10188/3/6E5129F2-8309-4EDE-BEEA-B2B32A39A5FB/wwdc2020_10188_sd.mp4",
"duration": 1809
},
"related": {
"activities": [
"wwdc2020-10646",
"wwdc2020-10663",
"wwdc2020-10740",
"wwdc2020-10743",
"wwdc2020-10744",
"wwdc2020-10836"
],
"resources": [
999,
998,
772,
771,
338,
247,
170
]
}
},
{
"id": "wwdc2020-10220",
"staticContentId": 3608,
"eventContentId": 10220,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10220",
"description": "Learn how to anticipate potential interruptions to your app’s interface and build smart tests to identify them. UI interruptions often appear indeterminately, typically during onboarding or first launch, which can make them hard to track down. Learn how to understand interruptions, write stronger tests with UI interruption handlers, and manage expected alerts.\r\n\r\nTo learn more about the latest improvements for testing your app in Xcode, check out “XCTSkip your tests”, “Get your test results faster”, and “Triage test failures with XCTIssue”.",
"title": "Handle interruptions and alerts in UI tests",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"keywords": [
"alerts",
"protected resources",
"testing",
"ui interruptions",
"ui testing",
"xcode"
],
"topicIds": [
38,
37,
36
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Interruption Handler Skeleton",
"startTimeSeconds": 304,
"endTimeSeconds": 312,
"language": "swift",
"code": "addUIInterruptionMonitor(withDescription: u003cspan class=\"syntax-string\"u003e\"Handle recipe update failures\"u003c/spanu003e) { element -u0026gt; u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// u003cspan class=\"syntax-doctag\"u003eTODO:u003c/spanu003e Use this handler to retry the update actionu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e\n}"
},
{
"title": "UI Test Method Body",
"startTimeSeconds": 316,
"endTimeSeconds": 375,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003etestRecipeDetailsNavigationu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e u003cspan class=\"syntax-keyword\"u003ethrowsu003c/spanu003e {\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e app = u003cspan class=\"syntax-type\"u003eXCUIApplicationu003c/spanu003e()\n app.launch()\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e pancakeRecipe = app.cells.staticTexts[u003cspan class=\"syntax-string\"u003e\"Fluffy Pancakes\"u003c/spanu003e].firstMatch\n pancakeRecipe.tap()\n\n u003cspan class=\"syntax-comment\"u003e// In the detail viewu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e detailTitle = app.navigationBars.staticTexts[u003cspan class=\"syntax-string\"u003e\"Fluffy Pancakes\"u003c/spanu003e].firstMatch\n u003cspan class=\"syntax-type\"u003eXCTAssertu003c/spanu003e(detailTitle.waitForExistence(timeout: u003cspan class=\"syntax-number\"u003e30u003c/spanu003e))\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e expectedImage = app.images[u003cspan class=\"syntax-string\"u003e\"Fluffy Pancakes Image\"u003c/spanu003e].firstMatch\n u003cspan class=\"syntax-type\"u003eXCTAssertu003c/spanu003e(expectedImage.exists)\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e ingredientsTitle = app.staticTexts[u003cspan class=\"syntax-string\"u003e\"Ingredients Title\"u003c/spanu003e].firstMatch\n u003cspan class=\"syntax-type\"u003eXCTAssertu003c/spanu003e(ingredientsTitle.exists)\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e ingredientsContent = app.textViews[u003cspan class=\"syntax-string\"u003e\"Ingredients Content\"u003c/spanu003e].firstMatch\n u003cspan class=\"syntax-type\"u003eXCTAssertu003c/spanu003e(ingredientsContent.exists)\n u003cspan class=\"syntax-type\"u003eXCTAssertu003c/spanu003e((ingredientsContent.value u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e! u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e).u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e u0026gt; u003cspan class=\"syntax-number\"u003e0u003c/spanu003e)\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e instructionsTitle = app.staticTexts[u003cspan class=\"syntax-string\"u003e\"Instructions Title\"u003c/spanu003e].firstMatch\n u003cspan class=\"syntax-type\"u003eXCTAssertu003c/spanu003e(instructionsTitle.exists)\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e instructionsTextView = app.textViews[u003cspan class=\"syntax-string\"u003e\"Instructions Content\"u003c/spanu003e].firstMatch\n u003cspan class=\"syntax-type\"u003eXCTAssertu003c/spanu003e(instructionsTextView.exists)\n u003cspan class=\"syntax-type\"u003eXCTAssertu003c/spanu003e((instructionsTextView.value u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e! u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e).u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e u0026gt; u003cspan class=\"syntax-number\"u003e0u003c/spanu003e)\n\n u003cspan class=\"syntax-comment\"u003e// Make sure we received the latest instructions:u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e expectedInstructions = u003cspan class=\"syntax-string\"u003e\"\"\"\n 1. Mix the flour, sugar, baking powder and salt.\n\n 2. Pour the milk, melted butter and egg into a well in the center and mix.\n\n 3. Heat a frying pan (don't forget to add a little bit of oil, grandson!), and fry until they're golden.\n\n 4. Optionally add maple syrup and/or fruits (they're healthy!).\n \"\"\"u003c/spanu003e\n u003cspan class=\"syntax-type\"u003eXCTAssertEqualu003c/spanu003e((instructionsTextView.value u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e! u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e), expectedInstructions)\n\n u003cspan class=\"syntax-comment\"u003e// Go back to the list of recipesu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e backButton = app.navigationBars.buttons[u003cspan class=\"syntax-string\"u003e\"Grandma's Recipes\"u003c/spanu003e].firstMatch\n backButton.tap()\n\n u003cspan class=\"syntax-type\"u003eXCTAssertu003c/spanu003e(pancakeRecipe.waitForExistence(timeout: u003cspan class=\"syntax-number\"u003e30u003c/spanu003e))\n}"
},
{
"title": "Modified Interruption Handler",
"startTimeSeconds": 380,
"endTimeSeconds": 419,
"language": "swift",
"code": "addUIInterruptionMonitor(withDescription: u003cspan class=\"syntax-string\"u003e\"Handle recipe update failures\"u003c/spanu003e) { element -u0026gt; u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e retryButton = element.buttons[u003cspan class=\"syntax-string\"u003e\"Retry\"u003c/spanu003e].firstMatch\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e element.elementType == .alert u0026amp;u0026amp; retryButton.exists {\n retryButton.tap()\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e\n } u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e\n }\n}"
},
{
"title": "Handle Expected Alerts",
"startTimeSeconds": 457,
"endTimeSeconds": 493,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003etestDeleteRecipeu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e u003cspan class=\"syntax-keyword\"u003ethrowsu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e breadCell = cell(recipeName: u003cspan class=\"syntax-string\"u003e\"Banana Bread\"u003c/spanu003e)\n deleteCell(breadCell)\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e alert = app.alerts[u003cspan class=\"syntax-string\"u003e\"Delete Recipe\"u003c/spanu003e].firstMatch\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e alertExists = alert.waitForExistence(timeout: u003cspan class=\"syntax-number\"u003e30u003c/spanu003e)\n u003cspan class=\"syntax-type\"u003eXCTAssertu003c/spanu003e(alertExists, u003cspan class=\"syntax-string\"u003e\"Expected alert to show up\"u003c/spanu003e)\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e description = u003cspan class=\"syntax-string\"u003e\"\"\"\n Are you sure you want to \\\n delete this recipe?\n \"\"\"u003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e alertDescription = alert.staticTexts[description]\n u003cspan class=\"syntax-type\"u003eXCTAssertu003c/spanu003e(alertDescription.exists)\n\n alert.buttons[u003cspan class=\"syntax-string\"u003e\"Delete\"u003c/spanu003e].tap()\n u003cspan class=\"syntax-type\"u003eXCTAssertFalseu003c/spanu003e(breadCell.exists)\n}"
},
{
"title": "Reset the Authorization Status of Protected Resources",
"startTimeSeconds": 629,
"endTimeSeconds": 656,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003etestAddingPhotosFirstTimeu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e u003cspan class=\"syntax-keyword\"u003ethrowsu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e app = u003cspan class=\"syntax-type\"u003eXCUIApplicationu003c/spanu003e()\n app.resetAuthorizationStatus(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: .photos)\n\n app.launch()\n\n u003cspan class=\"syntax-comment\"u003e// Test code…u003c/spanu003e\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10220/3/3529A3B2-1763-4B11-989D-D5B6B986EFE6/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10220/3/3529A3B2-1763-4B11-989D-D5B6B986EFE6/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10220/2/7415E714-0537-4978-954B-77EB031D8B17/transcripts/wwdc2020-10220-transcripts.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10220/3/3529A3B2-1763-4B11-989D-D5B6B986EFE6/wwdc2020_10220_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10220/3/3529A3B2-1763-4B11-989D-D5B6B986EFE6/wwdc2020_10220_sd.mp4",
"duration": 703
},
"related": {
"activities": [
"wwdc2020-10077",
"wwdc2020-10091",
"wwdc2020-10164",
"wwdc2020-10221",
"wwdc2020-10687",
"wwdc2018-702",
"wwdc2018-718"
],
"resources": [
1203,
1202
]
}
},
{
"id": "wwdc2020-10061",
"staticContentId": 3515,
"eventContentId": 10061,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10061",
"description": "Discover how you can enable Siri summoning for your music or audio app using SiriKit Media Intents. We’ll walk you through how to add Siri support to your music, podcast, or other audio service on more of our platforms, including HomePod and Apple TV, so people can start listening by just asking Siri. And learn about new APIs that let you support alternative results, helping people listen more quickly without leaving the Siri interface.",
"title": "Expand your SiriKit Media Intents to more platforms",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"tvOS",
"watchOS"
],
"keywords": [
"audio",
"audiobooks",
"conversational interaction",
"design",
"intents",
"intentsui",
"media",
"music",
"podcasts",
"siri",
"sirikit",
"sirikit media intents",
"siri remote",
"voice"
],
"topicIds": [
21,
13,
28
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "resolveMediaItems method",
"startTimeSeconds": 165,
"endTimeSeconds": 182,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eresolveMediaItemsu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e intent: INPlayMediaIntent, with completion: @escaping u003cspan class=\"syntax-params\"u003e([INPlayMediaMediaItemResolutionResult])u003c/spanu003eu003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e) {\n}"
},
{
"title": "handle with .continueInApp",
"startTimeSeconds": 183,
"endTimeSeconds": 211,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ehandleu003c/spanu003eu003cspan class=\"syntax-params\"u003e(intent: INPlayMediaIntent, completion: u003cspan class=\"syntax-params\"u003e(INPlayMediaIntentResponse)u003c/spanu003eu003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e) {\n completion(u003cspan class=\"syntax-type\"u003eINPlayMediaIntentResponseu003c/spanu003e(code: .continueInApp, userActivity: u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e))\n}"
},
{
"title": "Singular successWithResolvedMediaItem call",
"startTimeSeconds": 324,
"endTimeSeconds": 339,
"language": "swift",
"code": "u003cspan class=\"syntax-type\"u003eINPlayMediaMediaItemResolutionResultu003c/spanu003e.success(with: mediaItems[u003cspan class=\"syntax-number\"u003e0u003c/spanu003e])"
},
{
"title": "Plural successesWithResolvedMediaItems call",
"startTimeSeconds": 340,
"endTimeSeconds": 358,
"language": "swift",
"code": "u003cspan class=\"syntax-type\"u003eINPlayMediaMediaItemResolutionResultu003c/spanu003e.successes(with: mediaItems)"
},
{
"title": "handle with .handleInApp",
"startTimeSeconds": 367,
"endTimeSeconds": 384,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ehandleu003c/spanu003eu003cspan class=\"syntax-params\"u003e(intent: INPlayMediaIntent, completion: u003cspan class=\"syntax-params\"u003e(INPlayMediaIntentResponse)u003c/spanu003eu003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e) {\n completion(u003cspan class=\"syntax-type\"u003eINPlayMediaIntentResponseu003c/spanu003e(code: .handleInApp, userActivity: u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e))\n}"
},
{
"title": "ControlAudio resolveMediaItems",
"startTimeSeconds": 397,
"endTimeSeconds": 488,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eresolveMediaItemsu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e intent: INPlayMediaIntent, with completion: @escaping u003cspan class=\"syntax-params\"u003e([INPlayMediaMediaItemResolutionResult])u003c/spanu003eu003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e) {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e mediaSearch = intent.mediaSearch\n resolveMediaItems(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: mediaSearch) { optionalMediaItems u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e mediaItems = optionalMediaItems u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e\n }\n completion(u003cspan class=\"syntax-type\"u003eINPlayMediaMediaItemResolutionResultu003c/spanu003e.successes(with: mediaItems))\n }\n}"
},
{
"title": "App prewarming background appLaunch",
"startTimeSeconds": 624,
"endTimeSeconds": 645,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eapplicationu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: u003cspan class=\"syntax-keyword\"u003eAnyu003c/spanu003e]?)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Locate any app prewarming logic in this method -- fetch credentials, get audio player ready, etc.u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10061/7/0C05700A-690E-443C-9984-6792A466E6CA/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10061/7/0C05700A-690E-443C-9984-6792A466E6CA/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10061/7/0C05700A-690E-443C-9984-6792A466E6CA/transcripts/wwdc2020-10061-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10061/7/0C05700A-690E-443C-9984-6792A466E6CA/wwdc2020_10061_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10061/7/0C05700A-690E-443C-9984-6792A466E6CA/wwdc2020_10061_sd.mp4",
"duration": 686
},
"related": {
"activities": [
"wwdc2020-10060",
"wwdc2020-10068",
"wwdc2020-10069",
"wwdc2020-10071",
"wwdc2020-10073",
"wwdc2020-10074",
"wwdc2020-10083",
"wwdc2020-10084",
"wwdc2020-10086",
"wwdc2020-10087",
"wwdc2020-10088",
"wwdc2020-10190",
"wwdc2020-10200",
"wwdc2020-10203",
"wwdc2020-10694",
"wwdc2020-10914",
"wwdc2020-10963",
"tech-talks-10854"
],
"resources": [
1350,
1115,
1114,
893,
549
]
}
},
{
"id": "wwdc2020-10649",
"staticContentId": 3596,
"eventContentId": 10649,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10649",
"description": "The Xcode Library is an easy way for you to discover available SwiftUI views and drag and drop them to the Xcode Previews canvas, enabling rich visual editing of your app. We’ll show you how to extend the content of the Xcode Library with your own views and modifiers, optimizing for reusability and discoverability within your app or Swift packages.\r\n\r\nFor more on Xcode Previews, check out \"Structure your app for SwiftUI previews\", and \"Visually edit SwiftUI views\".",
"title": "Add custom views and modifiers to the Xcode Library",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"keywords": [
"library",
"modifiers",
"swiftui",
"views",
"xcode"
],
"topicIds": [
38
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "LibraryContentProvider",
"startTimeSeconds": 117,
"endTimeSeconds": 143,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eprotocolu003c/spanu003e u003cspan class=\"syntax-title\"u003eLibraryContentProvideru003c/spanu003e u003c/spanu003e{\n @u003cspan class=\"syntax-type\"u003eLibraryContentBuilderu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e views: [u003cspan class=\"syntax-type\"u003eLibraryItemu003c/spanu003e] { u003cspan class=\"syntax-keyword\"u003egetu003c/spanu003e }\n\n @u003cspan class=\"syntax-type\"u003eLibraryContentBuilderu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003emodifiersu003c/spanu003eu003cspan class=\"syntax-params\"u003e(base: ModifierBase)u003c/spanu003eu003c/spanu003e -u0026gt; [u003cspan class=\"syntax-type\"u003eLibraryItemu003c/spanu003e]\n}"
},
{
"title": "LibraryItem",
"startTimeSeconds": 152,
"endTimeSeconds": 167,
"language": "swift",
"code": "u003cspan class=\"syntax-type\"u003eLibraryItemu003c/spanu003e(\n u003cspan class=\"syntax-type\"u003eSmoothieRowViewu003c/spanu003e(smoothie: .lemonberry),\n visible: u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e,\n title: u003cspan class=\"syntax-string\"u003e\"Smoothie Row View\"u003c/spanu003e,\n category: .control\n)"
},
{
"title": "LibraryContent",
"startTimeSeconds": 202,
"endTimeSeconds": 503,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eLibraryContentu003c/spanu003e: u003cspan class=\"syntax-title\"u003eLibraryContentProvideru003c/spanu003e u003c/spanu003e{\n @u003cspan class=\"syntax-type\"u003eLibraryContentBuilderu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e views: [u003cspan class=\"syntax-type\"u003eLibraryItemu003c/spanu003e] {\n u003cspan class=\"syntax-type\"u003eLibraryItemu003c/spanu003e(\n u003cspan class=\"syntax-type\"u003eSmoothieRowViewu003c/spanu003e(smoothie: .lemonberry),\n category: .control\n )\n \n u003cspan class=\"syntax-type\"u003eLibraryItemu003c/spanu003e(\n u003cspan class=\"syntax-type\"u003eSmoothieRowViewu003c/spanu003e(smoothie: .lemonberry, showNearbyPopularity: u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e),\n title: u003cspan class=\"syntax-string\"u003e\"Smoothie Row View With Popularity\"u003c/spanu003e,\n category: .control\n )\n }\n}"
},
{
"title": "Image extension",
"startTimeSeconds": 537,
"endTimeSeconds": 553,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eextensionu003c/spanu003e u003cspan class=\"syntax-title\"u003eImageu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eresizedToFillu003c/spanu003eu003cspan class=\"syntax-params\"u003e(width: CGFloat, height: CGFloat)u003c/spanu003eu003c/spanu003e -u0026gt; some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e\n .resizable()\n .aspectRatio(contentMode: .fill)\n .frame(width: width, height: height)\n }\n}"
},
{
"title": "Modifiers",
"startTimeSeconds": 557,
"endTimeSeconds": 602,
"language": "swift",
"code": "@u003cspan class=\"syntax-type\"u003eLibraryContentBuilderu003c/spanu003e\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003emodifiersu003c/spanu003eu003cspan class=\"syntax-params\"u003e(base: Image)u003c/spanu003eu003c/spanu003e -u0026gt; [u003cspan class=\"syntax-type\"u003eLibraryItemu003c/spanu003e] {\n u003cspan class=\"syntax-type\"u003eLibraryItemu003c/spanu003e(\n base.resizedToFill(width: u003cspan class=\"syntax-number\"u003e100.0u003c/spanu003e, height: u003cspan class=\"syntax-number\"u003e100.0u003c/spanu003e)\n )\n }"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10649/5/904EDE80-6092-4438-85F6-0660C7586D01/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10649/5/904EDE80-6092-4438-85F6-0660C7586D01/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10649/4/01ACF20A-CE91-4DA6-984C-F8A9A5EBFA31/transcripts/wwdc2020-10649-transcripts.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10649/5/904EDE80-6092-4438-85F6-0660C7586D01/wwdc2020_10649_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10649/5/904EDE80-6092-4438-85F6-0660C7586D01/wwdc2020_10649_sd.mp4",
"duration": 791
},
"related": {
"activities": [
"wwdc2020-10149",
"wwdc2020-10185"
],
"resources": [
1187,
1186
]
}
},
{
"id": "wwdc2020-10030",
"staticContentId": 3358,
"eventContentId": 10030,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=yv6so7ie",
"description": "",
"title": "Widgets code-along",
"articleID": "01B922EB-9264-436A-B1C7-B73BCC68E4E1",
"articlePermalinkKey": "yv6so7ie",
"originalPublishingDate": "2020-06-22T01:00:02-07:00",
"publishingExpiryDate": "2025-06-22T00:35:17-07:00",
"platforms": [
"iOS",
"macOS"
],
"topicIds": [
36,
22,
13
],
"type": "Article",
"images": [
"square",
"wide"
],
"related": {
"activities": [
"wwdc2020-10028",
"wwdc2020-10041"
]
}
},
{
"id": "wwdc2020-10087",
"staticContentId": 3696,
"eventContentId": 10087,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10087",
"description": "The building blocks of the intelligent system are simple: Define, learn, execute. Discover how you can use intents to define your app's key features, create donations to help the system learn and make predictions about the future, and implement extensibility to ensure your app is ready to execute at just the right moment. Learn from teams at Apple about how their technologies use intents and donations in different ways, all for the same goal: to make the everyday easier.",
"title": "Design for intelligence: Make friends with \"The System\"",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"keywords": [
"donations",
"intelligence",
"intelligence system experience",
"intents",
"intentsui",
"shortcuts",
"shortcuts app",
"siri",
"sirikit",
"siri suggestions",
"suggestions",
"system intelligence",
"widgetkit",
"widgets"
],
"topicIds": [
39,
40,
21,
13,
6,
3
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10087/5/A416CA8C-0A29-45DD-9601-7245BE116636/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10087/5/A416CA8C-0A29-45DD-9601-7245BE116636/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10087/5/A416CA8C-0A29-45DD-9601-7245BE116636/transcripts/wwdc2020-10087-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10087/5/A416CA8C-0A29-45DD-9601-7245BE116636/wwdc2020_10087_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10087/5/A416CA8C-0A29-45DD-9601-7245BE116636/wwdc2020_10087_sd.mp4",
"duration": 1176
},
"related": {
"activities": [
"wwdc2020-10053",
"wwdc2020-10060",
"wwdc2020-10061",
"wwdc2020-10068",
"wwdc2020-10069",
"wwdc2020-10071",
"wwdc2020-10086",
"wwdc2020-10088",
"wwdc2020-10190",
"wwdc2020-10194",
"wwdc2020-10197",
"wwdc2020-10200",
"wwdc2020-10839",
"wwdc2020-10877",
"wwdc2020-10878",
"wwdc2020-10879",
"wwdc2020-10914",
"wwdc2020-10917",
"wwdc2020-10918",
"wwdc2020-10963",
"wwdc2020-10980"
],
"resources": [
1251,
1250
]
}
},
{
"id": "wwdc2020-10116",
"staticContentId": 3471,
"eventContentId": 10116,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10116",
"description": "Discover how you can integrate custom rotors and help people who use VoiceOver navigate complex situations within your app. Learn how custom rotors can help people explore even the most intricate interfaces, explore how to implement a custom rotor, and find out how rotors can improve navigation for someone who relies on VoiceOver.\r\n\r\nTo get the most out of this session, you should be familiar with general accessibility principles and VoiceOver accessibility APIs on iOS and iPadOS. For an overview, watch “Making Apps More Accessible with Custom Actions.”",
"title": "VoiceOver efficiency with custom rotors",
"originalPublishingDate": "2020-06-26T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS"
],
"keywords": [
"accessibility",
"custom rotors",
"related elements",
"rotors",
"text accessibility",
"uiaccessibilitycustomrotor",
"voiceover",
"voice over"
],
"topicIds": [
8
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "mapView.accessibilityCustomRotors = [customRotor(for: .stores), customRotor(for: .parks)]",
"startTimeSeconds": 244,
"endTimeSeconds": 262,
"language": "swift",
"code": "mapView.accessibilityCustomRotors = [customRotor(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: .stores), customRotor(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: .parks)]"
},
{
"title": "map rotor 1",
"startTimeSeconds": 271,
"endTimeSeconds": 296,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Custom map rotorsu003c/spanu003e\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ecustomRotoru003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e poiType: POI)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eUIAccessibilityCustomRotoru003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eUIAccessibilityCustomRotoru003c/spanu003e(name: poiType.rotorName) { [u003cspan class=\"syntax-keyword\"u003eunownedu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e] predicate u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-type\"u003eUIAccessibilityCustomRotorItemResultu003c/spanu003e( )\n }\n}"
},
{
"title": "map rotor 2",
"startTimeSeconds": 296,
"endTimeSeconds": 304,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Custom map rotorsu003c/spanu003e\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ecustomRotoru003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e poiType: POI)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eUIAccessibilityCustomRotoru003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eUIAccessibilityCustomRotoru003c/spanu003e(name: poiType.rotorName) { [u003cspan class=\"syntax-keyword\"u003eunownedu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e] predicate u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e currentElement = predicate.currentItem.targetElement u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e? u003cspan class=\"syntax-type\"u003eMKAnnotationViewu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e annotations = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.annotationViews(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: poiType)\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e currentIndex = annotations.firstIndex { $u003cspan class=\"syntax-number\"u003e0u003c/spanu003e == currentElement }\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-type\"u003eUIAccessibilityCustomRotorItemResultu003c/spanu003e( )\n\n }\n}"
},
{
"title": "map rotor 3",
"startTimeSeconds": 304,
"endTimeSeconds": 317,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Custom map rotorsu003c/spanu003e\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ecustomRotoru003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e poiType: POI)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eUIAccessibilityCustomRotoru003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eUIAccessibilityCustomRotoru003c/spanu003e(name: poiType.rotorName) { [u003cspan class=\"syntax-keyword\"u003eunownedu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e] predicate u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e currentElement = predicate.currentItem.targetElement u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e? u003cspan class=\"syntax-type\"u003eMKAnnotationViewu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e annotations = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.annotationViews(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: poiType)\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e currentIndex = annotations.firstIndex { $u003cspan class=\"syntax-number\"u003e0u003c/spanu003e == currentElement }\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e targetIndex: u003cspan class=\"syntax-type\"u003eIntu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eswitchu003c/spanu003e predicate.searchDirection {\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .previous:\n targetIndex = (currentIndex ?? u003cspan class=\"syntax-number\"u003e1u003c/spanu003e) - u003cspan class=\"syntax-number\"u003e1u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .next:\n targetIndex = (currentIndex ?? -u003cspan class=\"syntax-number\"u003e1u003c/spanu003e) + u003cspan class=\"syntax-number\"u003e1u003c/spanu003e\n }\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-type\"u003eUIAccessibilityCustomRotorItemResultu003c/spanu003e( )\n\n }\n}"
},
{
"title": "Maps rotor 4",
"startTimeSeconds": 317,
"endTimeSeconds": 333,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Custom map rotorsu003c/spanu003e\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ecustomRotoru003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e poiType: POI)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eUIAccessibilityCustomRotoru003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eUIAccessibilityCustomRotoru003c/spanu003e(name: poiType.rotorName) { [u003cspan class=\"syntax-keyword\"u003eunownedu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e] predicate u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e currentElement = predicate.currentItem.targetElement u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e? u003cspan class=\"syntax-type\"u003eMKAnnotationViewu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e annotations = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.annotationViews(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: poiType)\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e currentIndex = annotations.firstIndex { $u003cspan class=\"syntax-number\"u003e0u003c/spanu003e == currentElement }\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e targetIndex: u003cspan class=\"syntax-type\"u003eIntu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eswitchu003c/spanu003e predicate.searchDirection {\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .previous:\n targetIndex = (currentIndex ?? u003cspan class=\"syntax-number\"u003e1u003c/spanu003e) - u003cspan class=\"syntax-number\"u003e1u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .next:\n targetIndex = (currentIndex ?? -u003cspan class=\"syntax-number\"u003e1u003c/spanu003e) + u003cspan class=\"syntax-number\"u003e1u003c/spanu003e\n }\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-number\"u003e0u003c/spanu003e..u0026lt;annotations.u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e ~= targetIndex u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e { u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e } u003cspan class=\"syntax-comment\"u003e// Reached boundaryu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-type\"u003eUIAccessibilityCustomRotorItemResultu003c/spanu003e(targetElement: annotations[targetIndex],\n targetRange: u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e)\n }\n}"
},
{
"title": "Text rotor 1",
"startTimeSeconds": 487,
"endTimeSeconds": 500,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Custom text rotoru003c/spanu003e\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ecustomRotoru003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e attribute: NSAttributedString.Key)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eUIAccessibilityCustomRotoru003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eUIAccessibilityCustomRotoru003c/spanu003e(name: attribute.rotorName) { [u003cspan class=\"syntax-keyword\"u003eunownedu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e] predicate u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e targetRange: u003cspan class=\"syntax-type\"u003eUITextRange?u003c/spanu003e u003cspan class=\"syntax-comment\"u003e// Goal: find the range of following `attribute`u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e beginningRange = \n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e currentRange = u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e { u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e }\n\n u003cspan class=\"syntax-keyword\"u003eswitchu003c/spanu003e predicate.searchDirection { }\n\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-type\"u003eUIAccessibilityCustomRotorItemResultu003c/spanu003e(targetElement: u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e,\n targetRange: targetRange)\n }\n}"
},
{
"title": "Text rotor 2",
"startTimeSeconds": 500,
"endTimeSeconds": 517,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Custom text rotoru003c/spanu003e\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ecustomRotoru003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e attribute: NSAttributedString.Key)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eUIAccessibilityCustomRotoru003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eUIAccessibilityCustomRotoru003c/spanu003e(name: attribute.rotorName) { [u003cspan class=\"syntax-keyword\"u003eunownedu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e] predicate u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e targetRange: u003cspan class=\"syntax-type\"u003eUITextRange?u003c/spanu003e u003cspan class=\"syntax-comment\"u003e// Goal: find the range of following `attribute`u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e beginningRange = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.textRange(from: u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.beginningOfDocument,\n to: u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.beginningOfDocument)\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e currentRange = predicate.currentItem.targetRange ?? beginningRange u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e\n }\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e searchRange: u003cspan class=\"syntax-type\"u003eNSRangeu003c/spanu003e, searchOptions: u003cspan class=\"syntax-type\"u003eNSAttributedStringu003c/spanu003e.u003cspan class=\"syntax-type\"u003eEnumerationOptionsu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eswitchu003c/spanu003e predicate.searchDirection { }\n\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-type\"u003eUIAccessibilityCustomRotorItemResultu003c/spanu003e(targetElement: u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e,\n targetRange: targetRange)\n }\n}"
},
{
"title": "Text rotor 3",
"startTimeSeconds": 517,
"endTimeSeconds": 542,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Custom text rotoru003c/spanu003e\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ecustomRotoru003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e attribute: NSAttributedString.Key)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eUIAccessibilityCustomRotoru003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eUIAccessibilityCustomRotoru003c/spanu003e(name: attribute.rotorName) { [u003cspan class=\"syntax-keyword\"u003eunownedu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e] predicate u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e targetRange: u003cspan class=\"syntax-type\"u003eUITextRange?u003c/spanu003e u003cspan class=\"syntax-comment\"u003e// Goal: find the range of following `attribute`u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e beginningRange = \n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e currentRange = u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e { u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e }\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e searchRange: u003cspan class=\"syntax-type\"u003eNSRangeu003c/spanu003e, searchOptions: u003cspan class=\"syntax-type\"u003eNSAttributedStringu003c/spanu003e.u003cspan class=\"syntax-type\"u003eEnumerationOptionsu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eswitchu003c/spanu003e predicate.searchDirection {\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .previous:\n searchRange = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.rangeOfAttributedTextBefore(currentRange)\n searchOptions = [.u003cspan class=\"syntax-built_in\"u003ereverseu003c/spanu003e]\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .next:\n searchRange = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.rangeOfAttributedTextAfter(currentRange)\n searchOptions = []\n }\n \n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-type\"u003eUIAccessibilityCustomRotorItemResultu003c/spanu003e(targetElement: u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e,\n targetRange: targetRange)\n }\n}"
},
{
"title": "Text rotor 4 (end)",
"startTimeSeconds": 546,
"endTimeSeconds": 564,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Custom text rotoru003c/spanu003e\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ecustomRotoru003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e attribute: NSAttributedString.Key)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eUIAccessibilityCustomRotoru003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eUIAccessibilityCustomRotoru003c/spanu003e(name: attribute.rotorName) { [u003cspan class=\"syntax-keyword\"u003eunownedu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e] predicate u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e targetRange: u003cspan class=\"syntax-type\"u003eUITextRange?u003c/spanu003e u003cspan class=\"syntax-comment\"u003e// Goal: find the range of following `attribute`u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e beginningRange =\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e currentRange = u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e { u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e }\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e searchRange: u003cspan class=\"syntax-type\"u003eNSRangeu003c/spanu003e, searchOptions: u003cspan class=\"syntax-type\"u003eNSAttributedStringu003c/spanu003e.u003cspan class=\"syntax-type\"u003eEnumerationOptionsu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eswitchu003c/spanu003e predicate.searchDirection { }\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.attributedText.enumerateAttribute(\n attribute, u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e: searchRange, options: searchOptions) { value, range, stop u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e value != u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e { u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e }\n targetRange = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.textRange(from: range)\n stop.pointee = u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e\n }\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-type\"u003eUIAccessibilityCustomRotorItemResultu003c/spanu003e(targetElement: u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e,\n targetRange: targetRange)\n }\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10116/5/80EA07DE-B3B6-4DA6-80FE-BC03C5F0CB43/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10116/5/80EA07DE-B3B6-4DA6-80FE-BC03C5F0CB43/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10116/5/80EA07DE-B3B6-4DA6-80FE-BC03C5F0CB43/transcripts/wwdc2020-10116-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10116/5/80EA07DE-B3B6-4DA6-80FE-BC03C5F0CB43/wwdc2020_10116_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10116/5/80EA07DE-B3B6-4DA6-80FE-BC03C5F0CB43/wwdc2020_10116_sd.mp4",
"duration": 652
},
"related": {
"activities": [
"wwdc2020-10749",
"wwdc2020-10750",
"wwdc2020-10751",
"wwdc2019-250"
],
"resources": [
1071,
1070,
58
]
}
},
{
"id": "wwdc2020-10140",
"staticContentId": 3686,
"eventContentId": 10140,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10140",
"description": "Develop location-aware enterprise apps for your business and personalize your employee’s everyday experience. Learn how Apple built the Caffe Macs app for its on-campus cafeterias using iBeacons and Location Services and how you can apply these tools and frameworks to your own apps, while preserving employee privacy. From there, discover how you can use localization to deliver a great experience for your international employees.",
"title": "Build location-aware enterprise apps",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS"
],
"keywords": [
"core location",
"enterprise",
"ibeacon",
"internationalization",
"localization"
],
"topicIds": [
17,
42,
70
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Preferences: User-defined Preferred Location",
"startTimeSeconds": 208,
"endTimeSeconds": 221,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Storing the user’s preference using UserDefaultsu003c/spanu003e\n\nu003cspan class=\"syntax-type\"u003eUserDefaultsu003c/spanu003e.standard.u003cspan class=\"syntax-keyword\"u003esetu003c/spanu003e(defaultLocation.id, forKey: u003cspan class=\"syntax-string\"u003e\"defaultLocationId\"u003c/spanu003e)\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e defaultLocationId = u003cspan class=\"syntax-type\"u003eUserDefaultsu003c/spanu003e.standard.integer(forKey: u003cspan class=\"syntax-string\"u003e\"defaultLocationId\"u003c/spanu003e)"
},
{
"title": "Location Services: Requesting Authorization",
"startTimeSeconds": 374,
"endTimeSeconds": 420,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Add NSLocationWhenInUseUsageDescription to your Info.plist u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// e.g. “Location is required for placing orders while using the app.\"u003c/spanu003e\n\nlocationManager.requestWhenInUseAuthorization()\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003elocationManageru003c/spanu003eu003cspan class=\"syntax-params\"u003e(\n u003cspan class=\"syntax-number\"u003e_u003c/spanu003e manager: CLLocationManager,\n didChangeAuthorization status: CLAuthorizationStatus)u003c/spanu003eu003c/spanu003e {\n \n u003cspan class=\"syntax-keyword\"u003eswitchu003c/spanu003e status {\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .restricted, .denied: \n disableLocationFeatures()\n\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .authorizedWhenInUse, .authorizedAlways: \n enableLocationFeatures()\n\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .notDetermined: u003cspan class=\"syntax-comment\"u003e// The user hasn’t chosen an authorization statusu003c/spanu003e\n }\n}"
},
{
"title": "Location Services: Determining Device Support",
"startTimeSeconds": 422,
"endTimeSeconds": 436,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-type\"u003eCLLocationManageru003c/spanu003e.isMonitoringAvailable(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: u003cspan class=\"syntax-type\"u003eCLBeaconRegionu003c/spanu003e.u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e) {\n u003cspan class=\"syntax-comment\"u003e// Supports region monitoring to detect beacon regionsu003c/spanu003e\n}\n\nu003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-type\"u003eCLLocationManageru003c/spanu003e.isRangingAvailable() {\n u003cspan class=\"syntax-comment\"u003e// Supports obtaining the relative distance to a nearby iBeacon deviceu003c/spanu003e\n}"
},
{
"title": "Stage 1: Region Monitoring",
"startTimeSeconds": 534,
"endTimeSeconds": 570,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Stage 1: Region Monitoringu003c/spanu003e\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003emonitorBeaconsu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-type\"u003eCLLocationManageru003c/spanu003e.isMonitoringAvailable(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: u003cspan class=\"syntax-type\"u003eCLBeaconRegionu003c/spanu003e.u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e) {\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e constraint = u003cspan class=\"syntax-type\"u003eCLBeaconIdentityConstraintu003c/spanu003e(uuid: proximityUUID)\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e beaconRegion = u003cspan class=\"syntax-type\"u003eCLBeaconRegionu003c/spanu003e(\n beaconIdentityConstraint: constraint,\n identifier: beaconID\n )\n \n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.locationManager.startMonitoring(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: beaconRegion)\n }\n}"
},
{
"title": "Stage 2: Beacon Ranging",
"startTimeSeconds": 570,
"endTimeSeconds": 603,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Stage 2: Beacon Rangingu003c/spanu003e\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003elocationManageru003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e manager: CLLocationManager, didEnterRegion region: CLRegion)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e region = region u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e? u003cspan class=\"syntax-type\"u003eCLBeaconRegionu003c/spanu003e,\n u003cspan class=\"syntax-type\"u003eCLLocationManageru003c/spanu003e.isRangingAvailable()\n u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e { u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e }\n \n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e constraint = u003cspan class=\"syntax-type\"u003eCLBeaconIdentityConstraintu003c/spanu003e(uuid: region.uuid)\n manager.startRangingBeacons(satisfying: constraint)\n beaconsToRange.append(region)\n}\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003elocationManageru003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e manager: CLLocationManager, didExitRegion region: CLRegion)u003c/spanu003eu003c/spanu003e {\n \n}"
},
{
"title": "Stage 2: Beacon Ranging",
"startTimeSeconds": 609,
"endTimeSeconds": 626,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Stage 2: Beacon Rangingu003c/spanu003e\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003elocationManageru003c/spanu003eu003cspan class=\"syntax-params\"u003e(\n u003cspan class=\"syntax-number\"u003e_u003c/spanu003e manager: CLLocationManager,\n didRangeBeacons beacons: [CLBeacon],\n u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e region: CLBeaconRegion)u003c/spanu003eu003c/spanu003e {\n \n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e nearestBeacon = beacons.first u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e { u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e }\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e major = u003cspan class=\"syntax-type\"u003eCLBeaconMajorValueu003c/spanu003e(truncating: nearestBeacon.major)\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e minor = u003cspan class=\"syntax-type\"u003eCLBeaconMinorValueu003c/spanu003e(truncating: nearestBeacon.major)\n \n u003cspan class=\"syntax-keyword\"u003eswitchu003c/spanu003e nearestBeacon.proximity {\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .near, .immediate:\n displayInformation(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: major, and: minor)\n \n u003cspan class=\"syntax-keyword\"u003edefaultu003c/spanu003e:\n handleUnknownOrFarBeacon(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: major, and: minor)\n }\n}"
},
{
"title": "Formatting Dates",
"startTimeSeconds": 692,
"endTimeSeconds": 695,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Formatting Datesu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e dateFormatter = u003cspan class=\"syntax-type\"u003eDateFormatteru003c/spanu003e()\ndateFormatter.dateStyle = .medium\ndateFormatter.timeStyle = .short\ndateFormatter.string(from: u003cspan class=\"syntax-type\"u003eDateu003c/spanu003e())\nu003cspan class=\"syntax-comment\"u003e// \"Jun 25, 2020 at 9:41 AM\"u003c/spanu003e"
},
{
"title": "Configuring the Format of Currency",
"startTimeSeconds": 761,
"endTimeSeconds": 783,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Configuring the Format of Currencyu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e formatter = u003cspan class=\"syntax-type\"u003eNumberFormatteru003c/spanu003e()\nformatter.currencyCode = u003cspan class=\"syntax-string\"u003e\"CAD\"u003c/spanu003e\nformatter.numberStyle = .currency\nformatter.string(from: amount)\nu003cspan class=\"syntax-comment\"u003e// \"CA$1.00\"u003c/spanu003e"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10140/5/C86424DC-C2CF-464A-BDCE-35C9B4476E4B/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10140/5/C86424DC-C2CF-464A-BDCE-35C9B4476E4B/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10140/5/C86424DC-C2CF-464A-BDCE-35C9B4476E4B/transcripts/wwdc2020-10140-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10140/5/C86424DC-C2CF-464A-BDCE-35C9B4476E4B/wwdc2020_10140_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10140/5/C86424DC-C2CF-464A-BDCE-35C9B4476E4B/wwdc2020_10140_sd.mp4",
"duration": 856
},
"related": {
"activities": [
"wwdc2020-10160",
"wwdc2020-10162",
"wwdc2020-10219",
"wwdc2020-10638",
"wwdc2020-10660",
"wwdc2019-403",
"wwdc2019-705",
"wwdc2018-404"
],
"resources": [
1241,
1240
]
}
},
{
"id": "wwdc2020-10010",
"staticContentId": 3529,
"eventContentId": 10010,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10010",
"description": "Discover how to author and export high dynamic range (HDR) content in your app using AVFoundation. Learn about high dynamic range and how you can take advantage of it in your app. We’ll show you how to implement feature sets that allow people to export HDR content, go over supported HDR formats, review current restrictions, and explore the Apple platforms that support HDR export.",
"title": "Export HDR media in your app with AVFoundation",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS"
],
"topicIds": [
35,
31
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "AVAssetExportSession Intro",
"startTimeSeconds": 542,
"endTimeSeconds": 567,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// AVAssetExportSession code snippetu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e exportSession = u003cspan class=\"syntax-type\"u003eAVAssetExportSessionu003c/spanu003e(asset: sourceAsset,\n presetName: u003cspan class=\"syntax-type\"u003eAVAssetExportPresetHEVCHighestQualityu003c/spanu003e) u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n\tu003cspan class=\"syntax-comment\"u003e// Handle erroru003c/spanu003e\n}\n\nexportSession.outputURL = outputURL \nexportSession.outputFileType = u003cspan class=\"syntax-type\"u003eAVFileTypeQuickTimeMovieu003c/spanu003e \n\nexportSession.exportAsynchronouslyWithCompletionHandler {\n\tu003cspan class=\"syntax-comment\"u003e// Handle completion u003c/spanu003e\n}"
},
{
"title": "AVAssetWriter with sourceFormatHint",
"startTimeSeconds": 804,
"endTimeSeconds": 853,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// AVAssetWriter with sourceFormatHintu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e assetWriter = u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e u003cspan class=\"syntax-type\"u003eAVAssetWriteru003c/spanu003e(url: outputURL, fileType: u003cspan class=\"syntax-type\"u003eAVFileTypeQuickTimeMovieu003c/spanu003e)\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e outputSettings: [u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e: u003cspan class=\"syntax-type\"u003eAnyObjectu003c/spanu003e] = [\n\t\t\tu003cspan class=\"syntax-type\"u003eAVVideoCodecKeyu003c/spanu003e: u003cspan class=\"syntax-type\"u003eAVVideoCodecTypeHEVCu003c/spanu003e\n\t\t]\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e assetWriterInput = u003cspan class=\"syntax-type\"u003eAVAssetWriterInputu003c/spanu003e(mediaType: u003cspan class=\"syntax-type\"u003eAVMediaTypeVideou003c/spanu003e,\n outputSettings: outputSettings\n sourceFormatHint: videoFormatDescription)\n\nassetWriter.add(assetWriterInput)\n\nu003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e assetWriter.startWriting() u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n\tu003cspan class=\"syntax-keyword\"u003ethrowu003c/spanu003e assetWriter.error!\n}"
},
{
"title": "AVAssetWriter with AVOutputSettingsAssistant",
"startTimeSeconds": 853,
"endTimeSeconds": 937,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// AVAssetWriter with AVOutputSettingsAssistantu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e assetWriter = u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e u003cspan class=\"syntax-type\"u003eAVAssetWriteru003c/spanu003e(url: outputURL, fileType: u003cspan class=\"syntax-type\"u003eAVFileTypeQuickTimeMovieu003c/spanu003e)\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e settingsAssistant = u003cspan class=\"syntax-type\"u003eAVOutputSettingsAssistantu003c/spanu003e(\n preset: u003cspan class=\"syntax-type\"u003eAVOutputSettingsPresetu003c/spanu003e.hevc1920x1080)\n\nsettingsAssistant.sourceVideoFormat = videoFormatDescription\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e newVideoSettings = settingsAssistant.videoSettings\n\nu003cspan class=\"syntax-comment\"u003e// Modify a few fields in newVideoSettings hereu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e assetWriterInput = u003cspan class=\"syntax-type\"u003eAVAssetWriterInputu003c/spanu003e(mediaType: u003cspan class=\"syntax-type\"u003eAVMediaTypeVideou003c/spanu003e,\n outputSettings: newVideoSettings)\n\nassetWriter.add(assetWriterInput)\nu003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e assetWriter.startWriting() u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n\tu003cspan class=\"syntax-keyword\"u003ethrowu003c/spanu003e assetWriter.error!\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10010/4/BA038DF7-160D-47A0-B92D-DA6F71360CCA/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10010/4/BA038DF7-160D-47A0-B92D-DA6F71360CCA/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10010/4/BA038DF7-160D-47A0-B92D-DA6F71360CCA/transcripts/wwdc2020-10010-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10010/4/BA038DF7-160D-47A0-B92D-DA6F71360CCA/wwdc2020_10010_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10010/4/BA038DF7-160D-47A0-B92D-DA6F71360CCA/wwdc2020_10010_sd.mp4",
"duration": 1395
},
"related": {
"activities": [
"wwdc2020-10015",
"wwdc2020-10803",
"wwdc2020-10804"
],
"resources": [
1127,
1126,
574,
91
]
}
},
{
"id": "wwdc2020-10013",
"staticContentId": 3762,
"eventContentId": 10013,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10013",
"description": "Metal is a low-level, low-overhead hardware-accelerated graphics framework and shader application programming interface for producing stunning visual effects in applications. Discover how to make your shaders written in Metal Shading Language more programmable and extensible by using function pointers. Learn how to take advantage of this new feature for dynamic flow control in Metal shaders. Discover how to use function pointers to specify custom intersection fuctions in your ray tracing application. We’ll explain how function pointers allow several compilations models so you can balance GPU pipeline size against runtime performance.",
"title": "Get to know Metal function pointers",
"originalPublishingDate": "2020-06-26T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS"
],
"topicIds": [
27
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Our simple Path Tracer in Metal Shading Language:",
"startTimeSeconds": 189,
"endTimeSeconds": 207,
"language": "objectivec",
"code": "float3 shade(...);\n\n[[kernel]] u003cspan class=\"syntax-keyword\"u003evoidu003c/spanu003e rtKernel(...\n device Material *materials,\n constant Light u0026amp;light)\n{\n u003cspan class=\"syntax-comment\"u003e// ...u003c/spanu003e\n\n device Material u0026amp;material = materials[intersection.geometry_id];\n float3 result = shade(ray, triangleIntersectionData, material, light);\n\n u003cspan class=\"syntax-comment\"u003e// ...u003c/spanu003e\n}"
},
{
"title": "Our shading function",
"startTimeSeconds": 210,
"endTimeSeconds": 226,
"language": "objectivec",
"code": "float3 shade(...)\n{\n Lighting lighting = LightingFromLight(light, triangleIntersectionData);\n\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e CalculateLightingForMaterial(material, lighting, triangleIntersectionData);\n}"
},
{
"title": "Declare a function as visible",
"startTimeSeconds": 299,
"endTimeSeconds": 305,
"language": "objectivec",
"code": "[[visible]]\nLighting Area(Light light, TriangleIntersectionData triangleIntersectionData)\n{\n Lighting result;\n \n u003cspan class=\"syntax-comment\"u003e// Clever math code ...u003c/spanu003e\n \n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e result;\n}"
},
{
"title": "Single compilation pipeline on CPU",
"startTimeSeconds": 330,
"endTimeSeconds": 357,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Single compilation configurationu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e linkedFunctions = u003cspan class=\"syntax-type\"u003eMTLLinkedFunctionsu003c/spanu003e()\nlinkedFunctions.functions = [area, spot, sphere, hair, glass, skin]\ncomputeDescriptor.linkedFunctions = linkedFunctions\n\nu003cspan class=\"syntax-comment\"u003e// Pipeline creationu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e pipeline = u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e device.makeComputePipelineState(descriptor: computeDescriptor,\n options: [],\n reflection: u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e)"
},
{
"title": "Introducing MTLFunctionDescriptor",
"startTimeSeconds": 463,
"endTimeSeconds": 487,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Create by function descriptor:u003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e functionDescriptor = u003cspan class=\"syntax-type\"u003eMTLFunctionDescriptoru003c/spanu003e()\nfunctionDescriptor.name = u003cspan class=\"syntax-string\"u003e\"Area\"u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// More configuration goes hereu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e areaBinaryFunction = u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e library.makeFunction(descriptor: functionDescriptor)"
},
{
"title": "Binary pre–compilation",
"startTimeSeconds": 488,
"endTimeSeconds": 499,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Create and compile by function descriptor:u003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e functionDescriptor = u003cspan class=\"syntax-type\"u003eMTLFunctionDescriptoru003c/spanu003e()\nfunctionDescriptor.name = u003cspan class=\"syntax-string\"u003e\"Area\"u003c/spanu003e\nfunctionDescriptor.options = u003cspan class=\"syntax-type\"u003eMTLFunctionOptionsu003c/spanu003e.compileToBinary\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e areaBinaryFunction = u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e library.makeFunction(descriptor: functionDescriptor)"
},
{
"title": "Binary functions",
"startTimeSeconds": 500,
"endTimeSeconds": 526,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Specify binary functions on compute pipeline descriptoru003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e linkedFunctions = u003cspan class=\"syntax-type\"u003eMTLLinkedFunctionsu003c/spanu003e()\nlinkedFunctions.functions = [spot, sphere, hair, glass, skin]\nlinkedFunctions.binaryFunctions = [areaBinaryFunction]\ncomputeDescriptor.linkedFunctions = linkedFunctions\n\nu003cspan class=\"syntax-comment\"u003e// Pipeline creationu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e pipeline = u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e device.makeComputePipelineState(descriptor: computeDescriptor,\n options: [],\n reflection: u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e)"
},
{
"title": "Incremental compilation pipeline",
"startTimeSeconds": 664,
"endTimeSeconds": 704,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Create initial pipeline with optionu003c/spanu003e\ncomputeDescriptor.supportAddingBinaryFunctions = u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e\n\nu003cspan class=\"syntax-comment\"u003e// Create and compile by function descriptoru003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e functionDescriptor = u003cspan class=\"syntax-type\"u003eMTLFunctionDescriptoru003c/spanu003e()\nfunctionDescriptor.name = u003cspan class=\"syntax-string\"u003e\"Wood\"u003c/spanu003e\nfunctionDescriptor.options = u003cspan class=\"syntax-type\"u003eMTLFunctionOptionsu003c/spanu003e.compileToBinary\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e wood = u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e library.makeFunction(descriptor: functionDescriptor)\n\nu003cspan class=\"syntax-comment\"u003e// Create new pipeline from existing pipelineu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e newPipeline =\n u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e pipeline.makeComputePipelineStateWithAdditionalBinaryFunctions(functions: [wood])"
},
{
"title": "Visible function tables on the GPU",
"startTimeSeconds": 742,
"endTimeSeconds": 768,
"language": "objectivec",
"code": "u003cspan class=\"syntax-comment\"u003e// Helper using declaration in Metalu003c/spanu003e\nusing LightingFunction = Lighting(Light, TriangleIntersectionData);\nusing MaterialFunction = float3(Material, Lighting, TriangleIntersectionData);\n\nu003cspan class=\"syntax-comment\"u003e// Specify tables as kernel parametersu003c/spanu003e\nvisible_function_tableu0026lt;LightingFunctionu0026gt; lightingFunctions [[buffer(u003cspan class=\"syntax-number\"u003e1u003c/spanu003e)]],\nvisible_function_tableu0026lt;MaterialFunctionu0026gt; materialFunctions [[buffer(u003cspan class=\"syntax-number\"u003e2u003c/spanu003e)]],\n\nu003cspan class=\"syntax-comment\"u003e// Access via indexu003c/spanu003e\nLightingFunction *lightingFunction = lightingFunctions[light.index];\nLighting lighting = lightingFunction(light, triangleIntersection);\nu003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e materialFunctions[material.index](material, lighting, triangleIntersection);"
},
{
"title": "Visible function tables on the CPU",
"startTimeSeconds": 769,
"endTimeSeconds": 798,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Initialize descriptoru003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e vftDescriptor = u003cspan class=\"syntax-type\"u003eMTLVisibleFunctionTableDescriptoru003c/spanu003e()\nvftDescriptor.functionCount = u003cspan class=\"syntax-number\"u003e3u003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e lightingFunctionTable = pipeline.makeVisibleFunctionTable(descriptor: vftDescriptor)!\n\nu003cspan class=\"syntax-comment\"u003e// Find and set functions by handleu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e functionHandle = pipeline.functionHandle(function: spot)!\nlightingFunctionTable.setFunction(functionHandle, index:u003cspan class=\"syntax-number\"u003e0u003c/spanu003e)\n\nu003cspan class=\"syntax-comment\"u003e// Find and set functions by handleu003c/spanu003e\ncomputeCommandEncoder.setVisibleFunctionTable(lightingFunctionTable, bufferIndex:u003cspan class=\"syntax-number\"u003e1u003c/spanu003e)\nargumentEncoder.setVisibleFunctionTable(lightingFunctionTable, index:u003cspan class=\"syntax-number\"u003e1u003c/spanu003e)"
},
{
"title": "Function groups on GPU",
"startTimeSeconds": 863,
"endTimeSeconds": 888,
"language": "objectivec",
"code": "u003cspan class=\"syntax-comment\"u003e// Add function groups to our shading functionu003c/spanu003e\nfloat3 shade(...)\n{\n LightingFunction *lightingFunction = lightingFunctions[light.index];\n [[function_groups(u003cspan class=\"syntax-string\"u003e\"lighting\"u003c/spanu003e)]] Lighting lighting = lightingFunction(light,\ntriangleIntersection);\n \n MaterialFunction *materialFunction = materialFunctions[material.index];\n [[function_groups(u003cspan class=\"syntax-string\"u003e\"material\"u003c/spanu003e)]] float3 result = materialFunction(material, lighting, triangleIntersection);\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e result;\n}"
},
{
"title": "Function groups on CPU",
"startTimeSeconds": 889,
"endTimeSeconds": 925,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Function Group configurationu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e linkedFunctions = u003cspan class=\"syntax-type\"u003eMTLLinkedFunctionsu003c/spanu003e()\nlinkedFunctions.functions = [area, spot, sphere, hair, glass, skin]\nlinkedFunctions.groups = [u003cspan class=\"syntax-string\"u003e\"lighting\"u003c/spanu003e : [area, spot, sphere ],\n u003cspan class=\"syntax-string\"u003e\"material\"u003c/spanu003e : [hair, glass, skin ] ]\ncomputeDescriptor.linkedFunctions = linkedFunctions"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10013/4/17EAECF9-AE48-4108-B8E1-7214F30DC9AC/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10013/4/17EAECF9-AE48-4108-B8E1-7214F30DC9AC/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10013/4/17EAECF9-AE48-4108-B8E1-7214F30DC9AC/transcripts/wwdc2020-10013-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10013/4/17EAECF9-AE48-4108-B8E1-7214F30DC9AC/wwdc2020_10013_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10013/4/17EAECF9-AE48-4108-B8E1-7214F30DC9AC/wwdc2020_10013_sd.mp4",
"duration": 1231
},
"related": {
"activities": [
"wwdc2020-10018",
"wwdc2020-10813",
"wwdc2020-10816",
"wwdc2020-10817"
],
"resources": [
1281,
1280,
647,
525,
365,
357,
263,
56,
38,
31
]
}
},
{
"id": "wwdc2020-10736",
"staticContentId": 3802,
"eventContentId": 10736,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=e4u1mtfu",
"description": "",
"title": "Safari, Web, and Authentication",
"articleID": "92E11B93-5207-4EBE-9090-B82ADA0ECB26",
"articlePermalinkKey": "e4u1mtfu",
"originalPublishingDate": "2020-06-22T05:47:15-07:00",
"publishingExpiryDate": "2025-06-22T05:53:11-07:00",
"platforms": [
"iOS",
"macOS"
],
"topicIds": [
20
],
"type": "Article",
"images": [
"square",
"wide"
],
"related": {
"activities": [
"wwdc2020-10740",
"wwdc2020-10744",
"wwdc2020-10789",
"wwdc2020-10790"
]
}
},
{
"id": "wwdc2020-10104",
"staticContentId": 3364,
"eventContentId": 10104,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10104",
"description": "Make over your Mac apps: Discover how you can embrace the new design of macOS Big Sur and adopt its visual hierarchy, design patterns, and behaviors. We’ll explore the latest updates to AppKit around structural items and common controls, and show you how you can adapt more customized interfaces with just a bit of adoption work. And find out how you can incorporate custom accent colors and symbols to further personalize your app.\r\n\r\nTo get the most out of this session, you should be familiar with AppKit and SF Symbols. For additional information on symbols, watch \"SF Symbols 2.0”.",
"title": "Adopt the new look of macOS",
"originalPublishingDate": "2020-06-23T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"macOS"
],
"topicIds": [
22,
7,
6,
3
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Using a monochrome tint for \"secondary\" sidebar groups",
"startTimeSeconds": 225,
"endTimeSeconds": 291,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eoutlineViewu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e outlineView: NSOutlineView, tintConfigurationForItem item: u003cspan class=\"syntax-keyword\"u003eAnyu003c/spanu003e)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eNSTintConfiguration?u003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e sectionItem u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e u003cspan class=\"syntax-type\"u003eSectionItemu003c/spanu003e = item {\n u003cspan class=\"syntax-comment\"u003e/* \n This outline view uses a type called \"SectionItem\" to populate its top-level sections.\n Here we choose a tint configuration based on a hypothetical `isSecondarySection` property on that type.\n */u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e sectionItem.isSecondarySection ? .monochrome : .u003cspan class=\"syntax-keyword\"u003edefaultu003c/spanu003e\n }\n u003cspan class=\"syntax-comment\"u003e// For all other cases, a return value of `nil` indicates that the item should inherit a tint from its parent.u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e\n}"
},
{
"title": "Adopting NSSearchToolbarItem",
"startTimeSeconds": 692,
"endTimeSeconds": 718,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e searchItem = u003cspan class=\"syntax-type\"u003eNSSearchToolbarItemu003c/spanu003e(itemIdentifier: searchIdentifier)\nsearchItem.searchField = searchField"
},
{
"title": "Creating a split view tracking toolbar item",
"startTimeSeconds": 810,
"endTimeSeconds": 834,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e trackingItem = u003cspan class=\"syntax-type\"u003eNSTrackingSeparatorToolbarItemu003c/spanu003e(itemIdentifier: identifier,\n splitView: splitView,\n dividerIndex: u003cspan class=\"syntax-number\"u003e1u003c/spanu003e)"
},
{
"title": "Creating a large push button",
"startTimeSeconds": 1119,
"endTimeSeconds": 1132,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e button = u003cspan class=\"syntax-type\"u003eNSButtonu003c/spanu003e(title: u003cspan class=\"syntax-string\"u003e\"Get Started\"u003c/spanu003e, \n target: u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e, \n action: #selector(finishOnboarding(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e:)))\nbutton.controlSize = .large"
},
{
"title": "Instantiating a system symbol image",
"startTimeSeconds": 1475,
"endTimeSeconds": 1488,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e/* \n Symbol image names are literal descriptions of the symbol glyph, so we must\n include an accessibility description to provide semantic meaning to the image.\n */u003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e newFolderImage = u003cspan class=\"syntax-type\"u003eNSImageu003c/spanu003e(systemSymbolName: u003cspan class=\"syntax-string\"u003e\"plus.rectangle.on.folder\"u003c/spanu003e\n accessibilityDescription: u003cspan class=\"syntax-string\"u003e\"New Folder\"u003c/spanu003e)"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10104/8/2EE89376-B9BB-467A-B0F9-76651B382977/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10104/8/2EE89376-B9BB-467A-B0F9-76651B382977/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10104/8/2EE89376-B9BB-467A-B0F9-76651B382977/transcripts/wwdc2020-10104-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10104/8/2EE89376-B9BB-467A-B0F9-76651B382977/wwdc2020_10104_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10104/8/2EE89376-B9BB-467A-B0F9-76651B382977/wwdc2020_10104_sd.mp4",
"duration": 1723
},
"related": {
"activities": [
"wwdc2020-10143",
"wwdc2020-10207",
"wwdc2020-10895",
"wwdc2020-10896",
"wwdc2020-10897",
"wwdc2019-206"
],
"resources": [
959,
958
]
}
},
{
"id": "wwdc2020-10020",
"staticContentId": 3565,
"eventContentId": 10020,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10020",
"description": "When you design with accessibility in mind, you empower everyone to use your app. Discover how to create an adaptive interface for your app that takes a thoughtful approach to color, provides readable text, and accommodates other visual settings to maintain a great experience throughout.\r\n\r\nWe’ve designed this session like our user interfaces — to be accessible to all. If you’d like to learn even more about accessibility and design, you may also enjoy “Visual Design and Accessibility,” “Accessibility Inspector,” “Building Apps with Dynamic Type,” and “Introducing SF Symbols.”",
"title": "Make your app visually accessible",
"originalPublishingDate": "2020-06-23T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS"
],
"keywords": [
"accessibility",
"color",
"color blind",
"design",
"labels",
"reduce motion"
],
"topicIds": [
22,
8,
6
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Button Shapes",
"startTimeSeconds": 194,
"endTimeSeconds": 206,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eobserveButtonShapesNotificationu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Make buttons more visible by using shapes.u003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// If your default design does not include button shapes, observe this notification to make visual changes.u003c/spanu003e\n u003cspan class=\"syntax-type\"u003eNotificationCenteru003c/spanu003e.u003cspan class=\"syntax-keyword\"u003edefaultu003c/spanu003e.addObserver(u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e, selector: #selector(updateButtonShapes), name: u003cspan class=\"syntax-type\"u003eUIAccessibilityu003c/spanu003e.buttonShapesEnabledStatusDidChangeNotification, object: u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e)\n}\n\nu003cspan class=\"syntax-meta\"u003e@objcu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eupdateButtonShapesu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-type\"u003eUIAccessibilityu003c/spanu003e.buttonShapesEnabled {\n u003cspan class=\"syntax-comment\"u003e// Use extra visualizations for buttons.u003c/spanu003e\n } u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Use default design for buttons.u003c/spanu003e\n }\n}"
},
{
"title": "Differentiate Without Color",
"startTimeSeconds": 211,
"endTimeSeconds": 227,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eobserveDifferentiateWithoutColorNotificationu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Use symbols or shapes to convey meaning instead of relying on color alone.u003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// If your default design does not differentiate without color, observe this notification to make visual changes.u003c/spanu003e\n u003cspan class=\"syntax-type\"u003eNotificationCenteru003c/spanu003e.u003cspan class=\"syntax-keyword\"u003edefaultu003c/spanu003e.addObserver(u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e, selector: #selector(updateColorAndSymbols), name: u003cspan class=\"syntax-type\"u003eNSNotificationu003c/spanu003e.u003cspan class=\"syntax-type\"u003eNameu003c/spanu003e(u003cspan class=\"syntax-type\"u003eUIAccessibilityu003c/spanu003e.differentiateWithoutColorDidChangeNotification), object: u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e)\n}\n\nu003cspan class=\"syntax-meta\"u003e@objcu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eupdateColorAndSymbolsu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-type\"u003eUIAccessibilityu003c/spanu003e.shouldDifferentiateWithoutColor {\n u003cspan class=\"syntax-comment\"u003e// Use symbols or shapes to convey meaning.u003c/spanu003e\n } u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Use default design.u003c/spanu003e\n }\n}"
},
{
"title": "Smart Invert Colors",
"startTimeSeconds": 467,
"endTimeSeconds": 510,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eextensionu003c/spanu003e u003cspan class=\"syntax-title\"u003eUIViewu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-meta\"u003e@availableu003c/spanu003e(iOS u003cspan class=\"syntax-number\"u003e11.0u003c/spanu003e, tvOS u003cspan class=\"syntax-number\"u003e11.0u003c/spanu003e)\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e accessibilityIgnoresInvertColors: u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e { u003cspan class=\"syntax-keyword\"u003egetu003c/spanu003e u003cspan class=\"syntax-keyword\"u003esetu003c/spanu003e }\n}"
},
{
"title": "Large Text",
"startTimeSeconds": 597,
"endTimeSeconds": 657,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// ZodiacConstellationCell.swiftu003c/spanu003e\n\n\nu003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003etraitCollectionDidChangeu003c/spanu003e u003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e previousTraitCollection: UITraitCollection?)u003c/spanu003eu003c/spanu003e {\n\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e (traitCollection.preferredContentSizeCategory \n u0026lt; .accessibilityMedium) { u003cspan class=\"syntax-comment\"u003e// Default font sizesu003c/spanu003e\n\n stackView.axis = .horizontal\n stackView.alignment = .center\n\n } u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e { u003cspan class=\"syntax-comment\"u003e// Accessibility font sizesu003c/spanu003e\n\n stackView.axis = .vertical\n stackView.alignment = .leading\n\n }\n}"
},
{
"title": "Bold Text",
"startTimeSeconds": 693,
"endTimeSeconds": 718,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eobserveBoldTextNotificationu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Update labels to use bold or heavy font styles.u003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// If you aren't using system font styles, observe this notification to make visual changes.u003c/spanu003e\n u003cspan class=\"syntax-type\"u003eNotificationCenteru003c/spanu003e.u003cspan class=\"syntax-keyword\"u003edefaultu003c/spanu003e.addObserver(u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e, selector: #selector(updateLabelWeight), name: u003cspan class=\"syntax-type\"u003eUIAccessibilityu003c/spanu003e.boldTextStatusDidChangeNotification, object: u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e)\n}\n\nu003cspan class=\"syntax-meta\"u003e@objcu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eupdateLabelWeightu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-type\"u003eUIAccessibilityu003c/spanu003e.isBoldTextEnabled {\n u003cspan class=\"syntax-comment\"u003e// Use bold or heavy font weightu003c/spanu003e\n } u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Use font weight that is default to your design.u003c/spanu003e\n }\n}"
},
{
"title": "Reduce Motion",
"startTimeSeconds": 788,
"endTimeSeconds": 805,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eobserveReduceMotionNotificationu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Observe this notification to reduce or remove the frequency and intensity of motion effects.u003c/spanu003e\n u003cspan class=\"syntax-type\"u003eNotificationCenteru003c/spanu003e.u003cspan class=\"syntax-keyword\"u003edefaultu003c/spanu003e.addObserver(u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e, selector: #selector(updateMotionEffects), name: u003cspan class=\"syntax-type\"u003eUIAccessibilityu003c/spanu003e.reduceMotionStatusDidChangeNotification, object: u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e)\n}\n\nu003cspan class=\"syntax-meta\"u003e@objcu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eupdateMotionEffectsu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-type\"u003eUIAccessibilityu003c/spanu003e.isReduceMotionEnabled {\n u003cspan class=\"syntax-comment\"u003e// Reduce or remove extraneous motion effects.u003c/spanu003e\n } u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Use default motion effects.u003c/spanu003e\n }\n}"
},
{
"title": "Prefers Cross-fade Transitions",
"startTimeSeconds": 831,
"endTimeSeconds": 859,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eobserveCrossFadeTransitionsNotificationu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Reduce or remove sliding animations for transitioning views.u003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// If you aren't using system-provided navigation, observe this notification to make visual changes.u003c/spanu003e\n u003cspan class=\"syntax-type\"u003eNotificationCenteru003c/spanu003e.u003cspan class=\"syntax-keyword\"u003edefaultu003c/spanu003e.addObserver(u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e, selector: #selector(updateTransitionEffects), name: u003cspan class=\"syntax-type\"u003eUIAccessibilityu003c/spanu003e.prefersCrossFadeTransitionsStatusDidChange, object: u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e)\n}\n\nu003cspan class=\"syntax-meta\"u003e@objcu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eupdateTransitionEffectsu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-type\"u003eUIAccessibilityu003c/spanu003e.prefersCrossFadeTransitions {\n u003cspan class=\"syntax-comment\"u003e// Replace sliding transitions with cross-fade animations.u003c/spanu003e\n } u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Use default sliding transitions.u003c/spanu003e\n }\n}"
},
{
"title": "Reduce Transparency",
"startTimeSeconds": 907,
"endTimeSeconds": 917,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eobserveReduceTransparencyNotificationu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Reduce or remove transparency by adjusting these effects to be completely opaque.u003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// If you aren't using system-provided visual effects for blurs or vibrancy, observe this notification to make visual changes.u003c/spanu003e\n u003cspan class=\"syntax-type\"u003eNotificationCenteru003c/spanu003e.u003cspan class=\"syntax-keyword\"u003edefaultu003c/spanu003e.addObserver(u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e, selector: #selector(updateTransparencyEffects), name: u003cspan class=\"syntax-type\"u003eUIAccessibilityu003c/spanu003e.reduceTransparencyStatusDidChangeNotification, object: u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e)\n}\n\nu003cspan class=\"syntax-meta\"u003e@objcu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eupdateTransparencyEffectsu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-type\"u003eUIAccessibilityu003c/spanu003e.isReduceTransparencyEnabled {\n u003cspan class=\"syntax-comment\"u003e// Make transparency effects opaque.u003c/spanu003e\n } u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Use default transparency.u003c/spanu003e\n }\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10020/6/E082026F-7D80-4814-9A23-5A52E4CBF628/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10020/6/E082026F-7D80-4814-9A23-5A52E4CBF628/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10020/6/E082026F-7D80-4814-9A23-5A52E4CBF628/transcripts/wwdc2020-10020-transcripts.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10020/6/E082026F-7D80-4814-9A23-5A52E4CBF628/wwdc2020_10020_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10020/6/E082026F-7D80-4814-9A23-5A52E4CBF628/wwdc2020_10020_sd.mp4",
"duration": 964
},
"related": {
"activities": [
"wwdc2020-10692",
"wwdc2020-10749",
"wwdc2020-10750",
"wwdc2020-10751",
"wwdc2019-206",
"wwdc2019-244",
"wwdc2019-257",
"wwdc2017-245"
],
"resources": [
1145,
1144,
58
]
}
},
{
"id": "wwdc2020-10656",
"staticContentId": 3798,
"eventContentId": 10656,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10656",
"description": "Move beyond step counting in your app and give people a much richer understanding of their mobility. We’ll detail how you can take advantage of mobility metrics in iOS and watchOS to measure movement in more distinct and actionable ways. Learn about the latest HealthKit APIs for accessing mobility data, strategies for meaningful data aggregation, and how to interpret results for people using your app.",
"title": "Beyond counting steps",
"originalPublishingDate": "2020-06-26T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"watchOS"
],
"keywords": [
"motion",
"motionprocessor",
"pedometer",
"stairs",
"steps"
],
"topicIds": [
14
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10656/3/396B42E5-AAA7-4464-94DF-8F090FB4ED5E/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10656/3/396B42E5-AAA7-4464-94DF-8F090FB4ED5E/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10656/2/6F6B3D7A-6026-4C3D-8FB7-113BC003C548/transcripts/wwdc2020-10656-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10656/3/396B42E5-AAA7-4464-94DF-8F090FB4ED5E/wwdc2020_10656_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10656/3/396B42E5-AAA7-4464-94DF-8F090FB4ED5E/wwdc2020_10656_sd.mp4",
"duration": 1265
},
"related": {
"activities": [
"wwdc2020-10151",
"wwdc2020-10182",
"wwdc2020-10184",
"wwdc2020-10216",
"wwdc2020-10664",
"wwdc2020-10755",
"wwdc2020-10835",
"wwdc2020-10843"
],
"resources": [
1307,
1306,
506,
232,
87,
77
]
}
},
{
"id": "wwdc2020-10022",
"staticContentId": 3563,
"eventContentId": 10022,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10022",
"description": "Augment your app’s accessibility experience with speech synthesis: Discover the best times and places to add speech APIs so that everyone who uses your app can benefit. Learn how to use AVSpeechSynthesizer to complement assistive technologies like VoiceOver, and when to implement alternative APIs. And we’ll show you how to route audio to the appropriate source and create apps that integrate speech seamlessly for all who need or want it.\r\n\r\nTo get the most out of this session, you should be familiar with AVFoundation and the basics of speech synthesis. For an overview, watch “AVSpeechSynthesizer: Making iOS Talk.”",
"title": "Create a seamless speech experience in your apps",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS"
],
"keywords": [
"aac",
"alternative and augmentative communication",
"assistive technology",
"avspeechsynthesizer",
"avspeechutterance",
"speaking rate",
"speech properties",
"speech request",
"spoken content",
"utterance",
"voice technology"
],
"topicIds": [
8
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Post an Announcement to the Running Assistive Technology",
"startTimeSeconds": 85,
"endTimeSeconds": 105,
"language": "swift",
"code": "u003cspan class=\"syntax-type\"u003eUIAccessibilityu003c/spanu003e.post(notification: .announcement, argument: u003cspan class=\"syntax-string\"u003e\"Hello World\"u003c/spanu003e)"
},
{
"title": "Getting Started with AVSpeechSynthesizer",
"startTimeSeconds": 175,
"endTimeSeconds": 232,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.synthesizer = u003cspan class=\"syntax-type\"u003eAVSpeechSynthesizeru003c/spanu003e()\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e utterance = u003cspan class=\"syntax-type\"u003eAVSpeechUtteranceu003c/spanu003e(string: u003cspan class=\"syntax-string\"u003e\"Hello World\"u003c/spanu003e)\nu003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.synthesizer.speak(utterance)"
},
{
"title": "Respecting the Currently Running Assistive Technology's Speech Settings",
"startTimeSeconds": 248,
"endTimeSeconds": 298,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.synthesizer = u003cspan class=\"syntax-type\"u003eAVSpeechSynthesizeru003c/spanu003e()\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e utterance = u003cspan class=\"syntax-type\"u003eAVSpeechUtteranceu003c/spanu003e(string: u003cspan class=\"syntax-string\"u003e\"Hello World\"u003c/spanu003e)\nutterance.prefersAssistiveTechnologySettings = u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.synthesizer.speak(utterance)"
},
{
"title": "Customizing Speech - Choosing a Voice",
"startTimeSeconds": 342,
"endTimeSeconds": 376,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e utterance = u003cspan class=\"syntax-type\"u003eAVSpeechUtteranceu003c/spanu003e(string: u003cspan class=\"syntax-string\"u003e\"Hello World\"u003c/spanu003e)\n\nu003cspan class=\"syntax-comment\"u003e// Choose a voice using a language codeu003c/spanu003e\nutterance.voice = u003cspan class=\"syntax-type\"u003eAVSpeechSynthesisVoiceu003c/spanu003e(language: u003cspan class=\"syntax-string\"u003e\"en-US\"u003c/spanu003e)\n \nu003cspan class=\"syntax-comment\"u003e// Choose a voice using an identifieru003c/spanu003e\nutterance.voice = u003cspan class=\"syntax-type\"u003eAVSpeechSynthesisVoiceu003c/spanu003e(identifier: u003cspan class=\"syntax-type\"u003eAVSpeechSynthesisVoiceIdentifierAlexu003c/spanu003e)\n \nu003cspan class=\"syntax-comment\"u003e// Get a list of installed voicesu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e voices = u003cspan class=\"syntax-type\"u003eAVSpeechSynthesisVoiceu003c/spanu003e.speechVoices()"
},
{
"title": "Customizing Speech - Pitch and Rate",
"startTimeSeconds": 376,
"endTimeSeconds": 393,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e utterance = u003cspan class=\"syntax-type\"u003eAVSpeechUtteranceu003c/spanu003e(string: u003cspan class=\"syntax-string\"u003e\"Hello World\"u003c/spanu003e)\n\nu003cspan class=\"syntax-comment\"u003e// Choose a rate between 0 and 1, 0.5 is the default rateu003c/spanu003e\nutterance.rate = u003cspan class=\"syntax-number\"u003e0.75u003c/spanu003e\n \nu003cspan class=\"syntax-comment\"u003e// Choose a pitch multiplier between 0.5 and 2, 1 is the default multiplieru003c/spanu003e\nutterance.pitchMultiplier = u003cspan class=\"syntax-number\"u003e1.5u003c/spanu003e\n\nu003cspan class=\"syntax-comment\"u003e// Choose a volume between 0 and 1, 1 is the default valueu003c/spanu003e\nutterance.volume = u003cspan class=\"syntax-number\"u003e0.5u003c/spanu003e"
},
{
"title": "Mix Speech With an Outgoing Call",
"startTimeSeconds": 394,
"endTimeSeconds": 417,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.synthesizer = u003cspan class=\"syntax-type\"u003eAVSpeechSynthesizeru003c/spanu003e()\nu003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.synthesizer.mixToTelephonyUplink = u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e"
},
{
"title": "Opting Speech Out of Application's Audio Session",
"startTimeSeconds": 422,
"endTimeSeconds": 461,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.synthesizer = u003cspan class=\"syntax-type\"u003eAVSpeechSynthesizeru003c/spanu003e()\nu003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.synthesizer.usesApplicationAudioSession = u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10022/3/286D1613-442C-41FD-A8D9-B7E7E0AC8758/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10022/3/286D1613-442C-41FD-A8D9-B7E7E0AC8758/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10022/3/286D1613-442C-41FD-A8D9-B7E7E0AC8758/transcripts/wwdc2020-10022-transcripts.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10022/3/286D1613-442C-41FD-A8D9-B7E7E0AC8758/wwdc2020_10022_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10022/3/286D1613-442C-41FD-A8D9-B7E7E0AC8758/wwdc2020_10022_sd.mp4",
"duration": 519
},
"related": {
"activities": [
"wwdc2020-10749",
"wwdc2020-10750",
"wwdc2020-10751",
"wwdc2019-248",
"wwdc2018-236"
],
"resources": [
1143,
1142,
58
]
}
},
{
"id": "wwdc2020-10026",
"staticContentId": 3586,
"eventContentId": 10026,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10026",
"description": "Learn how to build lists and sidebars in your app with UICollectionView. Replace table view appearance while taking advantage of the full flexibility of compositional layout. Explore modular layout options and find out how they can unlock more design options for your apps than ever before. Find out how to combine table view-like lists with custom compositional layouts inside of a single UICollectionView. Discover how to work with lists, create richer cells, and customize your layout to create a well-designed presentation of information within your app.\r\n\r\nTo get the most out of this session, you should have a basic understanding of compositional layouts. Watch “Advances in Collection View Layout” from WWDC19 for more information.",
"title": "Lists in UICollectionView",
"originalPublishingDate": "2020-06-23T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS"
],
"keywords": [
"outline",
"sidebar",
"table",
"uitableview"
],
"topicIds": [
22
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Simple Setup",
"startTimeSeconds": 227,
"endTimeSeconds": 258,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Simple setupu003c/spanu003e\n \nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e configuration = u003cspan class=\"syntax-type\"u003eUICollectionLayoutListConfigurationu003c/spanu003e(appearance: .insetGrouped)\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e layout = u003cspan class=\"syntax-type\"u003eUICollectionViewCompositionalLayoutu003c/spanu003e.list(using: configuration)"
},
{
"title": "Per-Section Setup",
"startTimeSeconds": 265,
"endTimeSeconds": 278,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Per section setupu003c/spanu003e\n \nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e configuration = u003cspan class=\"syntax-type\"u003eUICollectionLayoutListConfigurationu003c/spanu003e(appearance: .insetGrouped)\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e section = u003cspan class=\"syntax-type\"u003eNSCollectionLayoutSectionu003c/spanu003e.list(using: configuration, layoutEnvironment: layoutEnvironment)"
},
{
"title": "Per-Section Setup full",
"startTimeSeconds": 280,
"endTimeSeconds": 317,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Per section setupu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e layout = u003cspan class=\"syntax-type\"u003eUICollectionViewCompositionalLayoutu003c/spanu003e() {\n [u003cspan class=\"syntax-keyword\"u003eweaku003c/spanu003e u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e] sectionIndex, layoutEnvironment u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e { u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e }\n\n u003cspan class=\"syntax-comment\"u003e// @todo: add custom layout sections for various sectionsu003c/spanu003e\n \n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e configuration = u003cspan class=\"syntax-type\"u003eUICollectionLayoutListConfigurationu003c/spanu003e(appearance: .insetGrouped)\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e section = u003cspan class=\"syntax-type\"u003eNSCollectionLayoutSectionu003c/spanu003e.list(using: configuration, layoutEnvironment: layoutEnvironment)\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e section\n}"
},
{
"title": "Header Mode Supplementary",
"startTimeSeconds": 349,
"endTimeSeconds": 399,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e configuration = u003cspan class=\"syntax-type\"u003eUICollectionLayoutListConfigurationu003c/spanu003e(appearance: .insetGrouped)\nconfiguration.headerMode = .supplementary\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e layout = u003cspan class=\"syntax-type\"u003eUICollectionViewCompositionalLayoutu003c/spanu003e.list(using: configuration)\n\ndataSource.supplementaryViewProvider = { (collectionView, elementKind, indexPath) u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e elementKind == u003cspan class=\"syntax-type\"u003eUICollectionViewu003c/spanu003e.elementKindSectionHeader {\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e collectionView.dequeueConfiguredReusableSupplementary(using: header, u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: indexPath)\n }\n u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e\n }\n}"
},
{
"title": "Header Mode Supplementary Optional Header",
"startTimeSeconds": 411,
"endTimeSeconds": 425,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e layout = u003cspan class=\"syntax-type\"u003eUICollectionViewCompositionalLayoutu003c/spanu003e() {\n [u003cspan class=\"syntax-keyword\"u003eweaku003c/spanu003e u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e] sectionIndex, layoutEnvironment u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e { u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e }\n\n u003cspan class=\"syntax-comment\"u003e// check if this section should show a header, e.g. by implementing a shouldShowHeader(for:) method.u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e sectionHasHeader = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.shouldShowHeader(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: sectionIndex)\n \n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e configuration = u003cspan class=\"syntax-type\"u003eUICollectionLayoutListConfigurationu003c/spanu003e(appearance: .insetGrouped)\n configuration.headerMode = sectionHasHeader ? .supplementary : .u003cspan class=\"syntax-keyword\"u003enoneu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e section = u003cspan class=\"syntax-type\"u003eNSCollectionLayoutSectionu003c/spanu003e.list(using: configuration, layoutEnvironment: layoutEnvironment)\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e section\n}"
},
{
"title": "Header Mode First Item In Section",
"startTimeSeconds": 427,
"endTimeSeconds": 452,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e configuration = u003cspan class=\"syntax-type\"u003eUICollectionLayoutListConfigurationu003c/spanu003e(appearance: .insetGrouped)\nconfiguration.headerMode = .firstItemInSection\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e layout = u003cspan class=\"syntax-type\"u003eUICollectionViewCompositionalLayoutu003c/spanu003e.list(using: configuration)"
},
{
"title": "Swipe Actions",
"startTimeSeconds": 700,
"endTimeSeconds": 800,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e cellRegistration = u003cspan class=\"syntax-type\"u003eUICollectionViewu003c/spanu003e.u003cspan class=\"syntax-type\"u003eCellRegistrationu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eUICollectionViewListCellu003c/spanu003e, u003cspan class=\"syntax-type\"u003eModelu003c/spanu003eu0026gt; { (cell, indexPath, item) u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// @todo configure the cell's contentu003c/spanu003e\n \n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e markFavorite = u003cspan class=\"syntax-type\"u003eUIContextualActionu003c/spanu003e(style: .normal, title: u003cspan class=\"syntax-string\"u003e\"Mark as Favorite\"u003c/spanu003e) {\n [u003cspan class=\"syntax-keyword\"u003eweaku003c/spanu003e u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e] (u003cspan class=\"syntax-number\"u003e_u003c/spanu003e, u003cspan class=\"syntax-number\"u003e_u003c/spanu003e, completion) u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e { u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e }\n u003cspan class=\"syntax-comment\"u003e// trigger the action with a reference to the modelu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.markItemAsFavorite(with: item.identifier)\n completion(u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e)\n }\n cell.leadingSwipeActionsConfiguration = u003cspan class=\"syntax-type\"u003eUISwipeActionsConfigurationu003c/spanu003e(actions: [markFavorite])\n}"
},
{
"title": "Accessories",
"startTimeSeconds": 895,
"endTimeSeconds": 945,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e cellRegistration = u003cspan class=\"syntax-type\"u003eUICollectionViewu003c/spanu003e.u003cspan class=\"syntax-type\"u003eCellRegistrationu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eUICollectionViewListCellu003c/spanu003e, u003cspan class=\"syntax-type\"u003eStringu003c/spanu003eu0026gt; { (cell, indexPath, item) u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// @todo configure the cell's contentu003c/spanu003e\n \n cell.accessories = [\n .disclosureIndicator(),\n .delete()\n ]\n}"
},
{
"title": "Accessories w/ Parameters",
"startTimeSeconds": 951,
"endTimeSeconds": 960,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e cellRegistration = u003cspan class=\"syntax-type\"u003eUICollectionViewu003c/spanu003e.u003cspan class=\"syntax-type\"u003eCellRegistrationu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eUICollectionViewListCellu003c/spanu003e, u003cspan class=\"syntax-type\"u003eStringu003c/spanu003eu0026gt; { (cell, indexPath, item) u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// @todo configure the cell's contentu003c/spanu003e\n \n cell.accessories = [\n .disclosureIndicator(displayed: .whenNotEditing),\n .delete()\n ]\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10026/6/9DBF6E96-B0C9-4104-B03E-F016434855BD/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10026/6/9DBF6E96-B0C9-4104-B03E-F016434855BD/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10026/6/9DBF6E96-B0C9-4104-B03E-F016434855BD/transcripts/wwdc2020-10026-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10026/6/9DBF6E96-B0C9-4104-B03E-F016434855BD/wwdc2020_10026_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10026/6/9DBF6E96-B0C9-4104-B03E-F016434855BD/wwdc2020_10026_sd.mp4",
"duration": 1014
},
"related": {
"activities": [
"wwdc2020-10027",
"wwdc2020-10045",
"wwdc2020-10097",
"wwdc2020-10105",
"wwdc2020-10907",
"wwdc2019-215"
],
"resources": [
1173,
1172,
530
]
}
},
{
"id": "wwdc2020-10224",
"staticContentId": 3428,
"eventContentId": 10224,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10224",
"description": "Fine-tune your audio app or plug-in for Apple silicon Macs: We’ll show you how to register your realtime threads using Audio Workgroups and make your app sing. Learn more about the power efficiency of System on a Chip (SoC) and how you can take advantage of new APIs to improve the speed and sound of your apps and plug-ins.",
"title": "Meet Audio Workgroups",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS"
],
"topicIds": [
28
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10224/4/C98E1064-6167-4594-A904-DE63C2C65B6B/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10224/4/C98E1064-6167-4594-A904-DE63C2C65B6B/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10224/3/4C783409-4E13-476C-8E3C-554B985A0F18/transcripts/wwdc2020-10224-transcripts.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10224/4/C98E1064-6167-4594-A904-DE63C2C65B6B/wwdc2020_10224_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10224/4/C98E1064-6167-4594-A904-DE63C2C65B6B/wwdc2020_10224_sd.mp4",
"duration": 652
},
"related": {
"activities": [
"wwdc2020-10852",
"wwdc2020-10859",
"wwdc2020-10864"
],
"resources": [
1023,
1022
]
}
},
{
"id": "wwdc2020-10690",
"staticContentId": 3884,
"eventContentId": 10690,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10690",
"description": "The Apple Design Awards recognize excellence in design and innovation for apps and games across all of Apple’s platforms. Meet the 2020 winners.",
"title": "2020 Apple Design Awards",
"originalPublishingDate": "2020-06-29T06:00:00-07:00",
"publishingExpiryDate": "2021-06-29T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"keywords": [
"ada",
"ada20",
"ada apps",
"ada games",
"adas",
"adas2020",
"ada winners",
"apple design",
"apple design awards",
"apple design awards 2020",
"apple designers",
"design",
"design awards",
"winners",
"winners 2020",
"winning apps",
"winning games"
],
"topicIds": [
26,
6,
3,
1
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10690/3/BEEE0B3F-1BD4-4333-BBB2-6B0999D91F6B/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10690/3/BEEE0B3F-1BD4-4333-BBB2-6B0999D91F6B/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10690/3/BEEE0B3F-1BD4-4333-BBB2-6B0999D91F6B/transcripts/wwdc2020-10690-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10690/3/BEEE0B3F-1BD4-4333-BBB2-6B0999D91F6B/Apple_ADA_Video_DevApp_UHD_2997fps_ProRes422HQ-unslated_1080p_dl.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10690/3/BEEE0B3F-1BD4-4333-BBB2-6B0999D91F6B/Apple_ADA_Video_DevApp_UHD_2997fps_ProRes422HQ-unslated_540p_dl.mp4",
"duration": 80
},
"related": {
"activities": [
"wwdc2020-20022",
"wwdc2019-104",
"wwdc2018-103",
"wwdc2018-801",
"wwdc2017-802"
],
"resources": [
834,
833,
832,
829
]
}
},
{
"id": "wwdc2020-10850",
"staticContentId": 4599,
"eventContentId": 10850,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=ejompdmj",
"description": "",
"title": "Friday",
"articleID": "9BFC3377-D3D0-46AA-A1B7-1DD79CEB85E1",
"articlePermalinkKey": "ejompdmj",
"originalPublishingDate": "2020-06-26T06:21:00-07:00",
"publishingExpiryDate": "2025-06-26T06:35:34-07:00",
"topicIds": [
],
"type": "Article",
"images": [
"square",
"wide"
]
},
{
"id": "wwdc2020-10100",
"staticContentId": 3380,
"eventContentId": 10100,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10100",
"description": "Show off your watchOS app’s complications and create a watch face worth sharing. Learn how to share watch faces inside your watchOS and iOS apps or host them on the web for anyone to find and download. We’ll also explore best practices for using watch face preview images, and show you how to create a smooth installation experience.",
"title": "Meet Watch Face Sharing",
"originalPublishingDate": "2020-06-26T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"watchOS"
],
"keywords": [
"⌚️",
"☕️",
"clockkit",
"complications",
"watchkit",
"watchos"
],
"topicIds": [
22,
20
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Detect Paired Watch",
"startTimeSeconds": 440,
"endTimeSeconds": 448,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e isPaired: u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e (u003cspan class=\"syntax-type\"u003eWCSessionu003c/spanu003e.isSupported()) {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e session = u003cspan class=\"syntax-type\"u003eWCSessionu003c/spanu003e.u003cspan class=\"syntax-keyword\"u003edefaultu003c/spanu003e\n session.delegate = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e\n session.activate()\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e session.isPaired\n } u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e\n }\n}"
},
{
"title": "Add Face Wrapper",
"startTimeSeconds": 541,
"endTimeSeconds": 555,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eprivateu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eaddFaceWrapperu003c/spanu003eu003cspan class=\"syntax-params\"u003e(withName: String)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e watchfaceURL = u003cspan class=\"syntax-type\"u003eBundleu003c/spanu003e.main.url(forResource: withName, withExtension: u003cspan class=\"syntax-string\"u003e\"watchface\"u003c/spanu003e) {\n u003cspan class=\"syntax-type\"u003eCLKWatchFaceLibraryu003c/spanu003e().addWatchFace(at: watchfaceURL, completionHandler: {\n (error: u003cspan class=\"syntax-type\"u003eError?u003c/spanu003e) u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e nsError = error u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e u003cspan class=\"syntax-type\"u003eNSError?u003c/spanu003e, nsError.code == u003cspan class=\"syntax-type\"u003eCLKWatchFaceLibraryu003c/spanu003e.u003cspan class=\"syntax-type\"u003eErrorCodeu003c/spanu003e.faceNotAvailable.rawValue {\n u003cspan class=\"syntax-built_in\"u003eprintu003c/spanu003e(nsError)\n }\n isLoading = u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e\n })\n }\n}"
},
{
"title": "Add Face Wrapper with Fallback Face",
"startTimeSeconds": 664,
"endTimeSeconds": 675,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eprivateu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eaddFaceWrapperu003c/spanu003eu003cspan class=\"syntax-params\"u003e(withName: String, fallbackName: String?)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e watchfaceURL = u003cspan class=\"syntax-type\"u003eBundleu003c/spanu003e.main.url(forResource: withName, withExtension: u003cspan class=\"syntax-string\"u003e\"watchface\"u003c/spanu003e) {\n u003cspan class=\"syntax-type\"u003eCLKWatchFaceLibraryu003c/spanu003e().addWatchFace(at: watchfaceURL, completionHandler: {\n (error: u003cspan class=\"syntax-type\"u003eError?u003c/spanu003e) u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e nsError = error u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e u003cspan class=\"syntax-type\"u003eNSError?u003c/spanu003e, nsError.code == u003cspan class=\"syntax-type\"u003eCLKWatchFaceLibraryu003c/spanu003e.u003cspan class=\"syntax-type\"u003eErrorCodeu003c/spanu003e.faceNotAvailable.rawValue {\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e name = fallbackName {\n u003cspan class=\"syntax-comment\"u003e// We failed, trying with fallbackName.u003c/spanu003e\n addFaceWrapper(withName: name, fallbackName: u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e)\n }\n }\n isLoading = u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e\n })\n }\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10100/2/880A8C5B-FB7B-456E-951B-5D13415E1B70/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10100/2/880A8C5B-FB7B-456E-951B-5D13415E1B70/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10100/2/880A8C5B-FB7B-456E-951B-5D13415E1B70/transcripts/wwdc2020-10100-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10100/2/880A8C5B-FB7B-456E-951B-5D13415E1B70/wwdc2020_10100_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10100/2/880A8C5B-FB7B-456E-951B-5D13415E1B70/wwdc2020_10100_sd.mp4",
"duration": 865
},
"related": {
"activities": [
"wwdc2020-10046",
"wwdc2020-10048",
"wwdc2020-10049",
"wwdc2020-10693",
"wwdc2020-10694",
"wwdc2020-10769",
"wwdc2020-10770",
"wwdc2020-20007"
],
"resources": [
1406,
1405,
973,
972,
430
]
}
},
{
"id": "wwdc2020-10735",
"staticContentId": 3803,
"eventContentId": 10735,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=m6ynwazb",
"description": "",
"title": "What’s new with in-app purchases and payments",
"articleID": "FC63716B-FEA4-4B51-AAC8-1B16181EB7E4",
"articlePermalinkKey": "m6ynwazb",
"originalPublishingDate": "2020-06-22T05:48:26-07:00",
"publishingExpiryDate": "2025-06-22T06:02:33-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"topicIds": [
],
"type": "Article",
"images": [
"square",
"wide"
]
},
{
"id": "wwdc2020-20020",
"staticContentId": 4598,
"eventContentId": 20020,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=xvdhdx93",
"description": "",
"title": "WWDC20 Daily Digest: Friday",
"articleID": "3A6FF8C1-75B1-4B96-B55B-6AEED762FE45",
"articlePermalinkKey": "xvdhdx93",
"originalPublishingDate": "2020-06-26T06:09:56-07:00",
"publishingExpiryDate": "2025-06-26T06:20:12-07:00",
"topicIds": [
],
"type": "Article",
"images": [
"square",
"wide"
]
},
{
"id": "wwdc2020-10048",
"staticContentId": 3378,
"eventContentId": 10048,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10048",
"description": "Spice up your graphic complications on Apple Watch using SwiftUI. We’ll teach you how to use custom SwiftUI views in complications on watch faces like Meridian and Infograph, look at some best practices when creating your complications, and show you how to preview your work in Xcode 12.\r\n\r\nTo get the most out of this session, you should be familiar with the basics of SwiftUI and building complications on Apple Watch. For an overview, watch “Create Complications for Apple Watch” and read “Building watchOS App Interfaces with SwiftUI.”\r\n\r\nOnce you’ve discovered how to build graphic complications in SwiftUI, you can combine this with other watchOS 7 features like multiple complications and Face Sharing to create a watch face packed with personality and customized for people who love your app.",
"title": "Build complications in SwiftUI",
"originalPublishingDate": "2020-06-23T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"watchOS"
],
"keywords": [
"⌚️",
"clockkit",
"watchkit",
"watchos"
],
"topicIds": [
22
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Relative Text",
"startTimeSeconds": 197,
"endTimeSeconds": 205,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e SwiftUI\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e ClockKit\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eRelativeTextu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eVStacku003c/spanu003e(alignment: .leading) {\n u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Count Down\"u003c/spanu003e)\n .font(.headline)\n .foregroundColor(.accentColor)\n u003cspan class=\"syntax-type\"u003eLabelu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Nap Time\"u003c/spanu003e, systemImage: u003cspan class=\"syntax-string\"u003e\"moon.fill\"u003c/spanu003e)\n u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(u003cspan class=\"syntax-type\"u003eDateu003c/spanu003e() + u003cspan class=\"syntax-number\"u003e100u003c/spanu003e, style: .relative)\n }\n .frame(maxWidth: .infinity, alignment: .leading)\n }\n}\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eRelativeText_Previewsu003c/spanu003e: u003cspan class=\"syntax-title\"u003ePreviewProvideru003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003estaticu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e previews: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eCLKComplicationTemplateGraphicRectangularFullViewu003c/spanu003e(u003cspan class=\"syntax-type\"u003eRelativeTextu003c/spanu003e())\n .previewContext()\n }\n}"
},
{
"title": "Timer Text",
"startTimeSeconds": 206,
"endTimeSeconds": 214,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e SwiftUI\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e ClockKit\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eTimerTextu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eVStacku003c/spanu003e(alignment: .leading) {\n u003cspan class=\"syntax-type\"u003eLabelu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Sourdough Timer\"u003c/spanu003e, systemImage: u003cspan class=\"syntax-string\"u003e\"timer\"u003c/spanu003e)\n .foregroundColor(.orange)\n u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Time remaining: \\(Date() + 100, style: .timer)\"u003c/spanu003e)\n }\n .frame(maxWidth: .infinity, alignment: .leading)\n }\n}\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eTimerText_Previewsu003c/spanu003e: u003cspan class=\"syntax-title\"u003ePreviewProvideru003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003estaticu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e previews: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eCLKComplicationTemplateGraphicRectangularFullViewu003c/spanu003e(u003cspan class=\"syntax-type\"u003eTimerTextu003c/spanu003e())\n .previewContext()\n }\n}"
},
{
"title": "Progress View Sample #1",
"startTimeSeconds": 244,
"endTimeSeconds": 254,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e SwiftUI\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e ClockKit\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eProgressSampleu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eProgressViewu003c/spanu003e(value: u003cspan class=\"syntax-number\"u003e0.7u003c/spanu003e)\n .progressViewStyle(u003cspan class=\"syntax-type\"u003eCircularProgressViewStyleu003c/spanu003e())\n }\n}\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eProgressSample_Previewsu003c/spanu003e: u003cspan class=\"syntax-title\"u003ePreviewProvideru003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003estaticu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e previews: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eCLKComplicationTemplateGraphicCircularViewu003c/spanu003e(u003cspan class=\"syntax-type\"u003eProgressSampleu003c/spanu003e())\n .previewContext()\n }\n}"
},
{
"title": "Progress View Sample #2",
"startTimeSeconds": 255,
"endTimeSeconds": 262,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e SwiftUI\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e ClockKit\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eProgressSampleu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eProgressViewu003c/spanu003e(value: u003cspan class=\"syntax-number\"u003e0.7u003c/spanu003e) {\n u003cspan class=\"syntax-type\"u003eImageu003c/spanu003e(systemName: u003cspan class=\"syntax-string\"u003e\"music.note\"u003c/spanu003e)\n }\n .progressViewStyle(u003cspan class=\"syntax-type\"u003eCircularProgressViewStyleu003c/spanu003e())\n }\n}\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eProgressSample_Previewsu003c/spanu003e: u003cspan class=\"syntax-title\"u003ePreviewProvideru003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003estaticu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e previews: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eCLKComplicationTemplateGraphicCircularViewu003c/spanu003e(u003cspan class=\"syntax-type\"u003eProgressSampleu003c/spanu003e())\n .previewContext()\n }\n}"
},
{
"title": "Progress View Sample #3",
"startTimeSeconds": 263,
"endTimeSeconds": 268,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e SwiftUI\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e ClockKit\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eProgressSampleu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eProgressViewu003c/spanu003e(value: u003cspan class=\"syntax-number\"u003e0.7u003c/spanu003e) {\n u003cspan class=\"syntax-type\"u003eImageu003c/spanu003e(systemName: u003cspan class=\"syntax-string\"u003e\"music.note\"u003c/spanu003e)\n }\n .progressViewStyle(u003cspan class=\"syntax-type\"u003eCircularProgressViewStyleu003c/spanu003e(tint: .red))\n }\n}\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eProgressSample_Previewsu003c/spanu003e: u003cspan class=\"syntax-title\"u003ePreviewProvideru003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003estaticu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e previews: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eCLKComplicationTemplateGraphicCircularViewu003c/spanu003e(u003cspan class=\"syntax-type\"u003eProgressSampleu003c/spanu003e())\n .previewContext()\n }\n}"
},
{
"title": "Progress View Sample #4",
"startTimeSeconds": 269,
"endTimeSeconds": 275,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e SwiftUI\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e ClockKit\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eProgressSampleu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eVStacku003c/spanu003e(alignment: .leading) {\n u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Water Reminder\"u003c/spanu003e)\n .foregroundColor(.blue)\n u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"32 oz. consumed\"u003c/spanu003e)\n u003cspan class=\"syntax-type\"u003eProgressViewu003c/spanu003e(value: u003cspan class=\"syntax-number\"u003e0.7u003c/spanu003e)\n .progressViewStyle(u003cspan class=\"syntax-type\"u003eLinearProgressViewStyleu003c/spanu003e(tint: .blue))\n }\n \n }\n}\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eProgressSample_Previewsu003c/spanu003e: u003cspan class=\"syntax-title\"u003ePreviewProvideru003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003estaticu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e previews: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eCLKComplicationTemplateGraphicRectangularFullViewu003c/spanu003e(u003cspan class=\"syntax-type\"u003eProgressSampleu003c/spanu003e())\n .previewContext()\n }\n}"
},
{
"title": "Gauge Sample #1",
"startTimeSeconds": 285,
"endTimeSeconds": 294,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e SwiftUI\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e ClockKit\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eGaugeSampleu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eGaugeu003c/spanu003e(value: u003cspan class=\"syntax-number\"u003e5.8u003c/spanu003e, u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e: u003cspan class=\"syntax-number\"u003e3u003c/spanu003e...u003cspan class=\"syntax-number\"u003e10u003c/spanu003e) {\n u003cspan class=\"syntax-type\"u003eImageu003c/spanu003e(systemName: u003cspan class=\"syntax-string\"u003e\"drop.fill\"u003c/spanu003e)\n .foregroundColor(.green)\n }\n .gaugeStyle(u003cspan class=\"syntax-type\"u003eCircularGaugeStyleu003c/spanu003e())\n }\n}\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eGaugeSample_Previewsu003c/spanu003e: u003cspan class=\"syntax-title\"u003ePreviewProvideru003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003estaticu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e previews: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eCLKComplicationTemplateGraphicCircularViewu003c/spanu003e(u003cspan class=\"syntax-type\"u003eGaugeSampleu003c/spanu003e())\n .previewContext()\n }\n}"
},
{
"title": "Gauge Sample #2",
"startTimeSeconds": 295,
"endTimeSeconds": 301,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e SwiftUI\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e ClockKit\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eGaugeSampleu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n @u003cspan class=\"syntax-type\"u003eStateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e acidity = u003cspan class=\"syntax-number\"u003e5.8u003c/spanu003e\n \n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eGaugeu003c/spanu003e(value: acidity, u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e: u003cspan class=\"syntax-number\"u003e3u003c/spanu003e...u003cspan class=\"syntax-number\"u003e10u003c/spanu003e) {\n u003cspan class=\"syntax-type\"u003eImageu003c/spanu003e(systemName: u003cspan class=\"syntax-string\"u003e\"drop.fill\"u003c/spanu003e)\n .foregroundColor(.green)\n } currentValueLabel: {\n u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"\\(acidity, specifier: \"u003c/spanu003e%.1fu003cspan class=\"syntax-string\"u003e\")\"u003c/spanu003e)\n }\n .gaugeStyle(u003cspan class=\"syntax-type\"u003eCircularGaugeStyleu003c/spanu003e())\n }\n}\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eGaugeSample_Previewsu003c/spanu003e: u003cspan class=\"syntax-title\"u003ePreviewProvideru003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003estaticu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e previews: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eCLKComplicationTemplateGraphicCircularViewu003c/spanu003e(u003cspan class=\"syntax-type\"u003eGaugeSampleu003c/spanu003e())\n .previewContext()\n }\n}"
},
{
"title": "Gauge Sample #3",
"startTimeSeconds": 302,
"endTimeSeconds": 313,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e SwiftUI\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e ClockKit\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eGaugeSampleu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n @u003cspan class=\"syntax-type\"u003eStateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e acidity = u003cspan class=\"syntax-number\"u003e5.8u003c/spanu003e\n \n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eGaugeu003c/spanu003e(value: acidity, u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e: u003cspan class=\"syntax-number\"u003e3u003c/spanu003e...u003cspan class=\"syntax-number\"u003e10u003c/spanu003e) {\n u003cspan class=\"syntax-type\"u003eImageu003c/spanu003e(systemName: u003cspan class=\"syntax-string\"u003e\"drop.fill\"u003c/spanu003e)\n .foregroundColor(.green)\n } currentValueLabel: {\n u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"\\(acidity, specifier: \"u003c/spanu003e%.1fu003cspan class=\"syntax-string\"u003e\")\"u003c/spanu003e)\n } minimumValueLabel: {\n u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"3\"u003c/spanu003e)\n } maximumValueLabel: {\n u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"10\"u003c/spanu003e)\n }\n .gaugeStyle(u003cspan class=\"syntax-type\"u003eCircularGaugeStyleu003c/spanu003e())\n }\n}\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eGaugeSample_Previewsu003c/spanu003e: u003cspan class=\"syntax-title\"u003ePreviewProvideru003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003estaticu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e previews: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eCLKComplicationTemplateGraphicCircularViewu003c/spanu003e(u003cspan class=\"syntax-type\"u003eGaugeSampleu003c/spanu003e())\n .previewContext()\n }\n}"
},
{
"title": "Gauge Sample #4",
"startTimeSeconds": 314,
"endTimeSeconds": 319,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e SwiftUI\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e ClockKit\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eGaugeSampleu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n @u003cspan class=\"syntax-type\"u003eStateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e acidity = u003cspan class=\"syntax-number\"u003e5.8u003c/spanu003e\n \n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eGaugeu003c/spanu003e(value: acidity, u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e: u003cspan class=\"syntax-number\"u003e3u003c/spanu003e...u003cspan class=\"syntax-number\"u003e10u003c/spanu003e) {\n u003cspan class=\"syntax-type\"u003eImageu003c/spanu003e(systemName: u003cspan class=\"syntax-string\"u003e\"drop.fill\"u003c/spanu003e)\n .foregroundColor(.green)\n } currentValueLabel: {\n u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"\\(acidity, specifier: \"u003c/spanu003e%.1fu003cspan class=\"syntax-string\"u003e\")\"u003c/spanu003e)\n } minimumValueLabel: {\n u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"3\"u003c/spanu003e)\n } maximumValueLabel: {\n u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"10\"u003c/spanu003e)\n }\n .gaugeStyle(u003cspan class=\"syntax-type\"u003eCircularGaugeStyleu003c/spanu003e(tint: .green))\n }\n}\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eGaugeSample_Previewsu003c/spanu003e: u003cspan class=\"syntax-title\"u003ePreviewProvideru003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003estaticu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e previews: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eCLKComplicationTemplateGraphicCircularViewu003c/spanu003e(u003cspan class=\"syntax-type\"u003eGaugeSampleu003c/spanu003e())\n .previewContext()\n }\n}"
},
{
"title": "Gauge Sample #5",
"startTimeSeconds": 321,
"endTimeSeconds": 333,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e SwiftUI\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e ClockKit\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eGaugeSampleu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n @u003cspan class=\"syntax-type\"u003eStateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e acidity = u003cspan class=\"syntax-number\"u003e5.8u003c/spanu003e\n \n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eGaugeu003c/spanu003e(value: acidity, u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e: u003cspan class=\"syntax-number\"u003e3u003c/spanu003e...u003cspan class=\"syntax-number\"u003e10u003c/spanu003e) {\n u003cspan class=\"syntax-type\"u003eImageu003c/spanu003e(systemName: u003cspan class=\"syntax-string\"u003e\"drop.fill\"u003c/spanu003e)\n .foregroundColor(.green)\n } currentValueLabel: {\n u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"\\(acidity, specifier: \"u003c/spanu003e%.1fu003cspan class=\"syntax-string\"u003e\")\"u003c/spanu003e)\n } minimumValueLabel: {\n u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"3\"u003c/spanu003e)\n } maximumValueLabel: {\n u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"10\"u003c/spanu003e)\n }\n .gaugeStyle(\n u003cspan class=\"syntax-type\"u003eCircularGaugeStyleu003c/spanu003e(\n tint: u003cspan class=\"syntax-type\"u003eGradientu003c/spanu003e(colors: [.orange, .yellow, .green, .blue, .purple])\n )\n )\n }\n}\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eGaugeSample_Previewsu003c/spanu003e: u003cspan class=\"syntax-title\"u003ePreviewProvideru003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003estaticu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e previews: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eCLKComplicationTemplateGraphicCircularViewu003c/spanu003e(u003cspan class=\"syntax-type\"u003eGaugeSampleu003c/spanu003e())\n .previewContext()\n }\n}"
},
{
"title": "Gauge Sample #6",
"startTimeSeconds": 334,
"endTimeSeconds": 338,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e SwiftUI\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e ClockKit\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eGaugeSampleu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n @u003cspan class=\"syntax-type\"u003eStateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e acidity = u003cspan class=\"syntax-number\"u003e5.8u003c/spanu003e\n \n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eVStacku003c/spanu003e(alignment: .leading) {\n u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Garden Soil Acidity\"u003c/spanu003e)\n .foregroundColor(.green)\n u003cspan class=\"syntax-type\"u003eGaugeu003c/spanu003e(value: acidity, u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e: u003cspan class=\"syntax-number\"u003e3u003c/spanu003e...u003cspan class=\"syntax-number\"u003e10u003c/spanu003e) {\n u003cspan class=\"syntax-type\"u003eImageu003c/spanu003e(systemName: u003cspan class=\"syntax-string\"u003e\"drop.fill\"u003c/spanu003e)\n .foregroundColor(.green)\n } currentValueLabel: {\n u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"\\(acidity, specifier: \"u003c/spanu003e%.1fu003cspan class=\"syntax-string\"u003e\")\"u003c/spanu003e)\n } minimumValueLabel: {\n u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"3\"u003c/spanu003e)\n } maximumValueLabel: {\n u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"10\"u003c/spanu003e)\n }\n .gaugeStyle(\n u003cspan class=\"syntax-type\"u003eLinearGaugeStyleu003c/spanu003e(\n tint: u003cspan class=\"syntax-type\"u003eGradientu003c/spanu003e(colors: [.orange, .yellow, .green, .blue, .purple])\n )\n )\n }\n }\n}\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eGaugeSample_Previewsu003c/spanu003e: u003cspan class=\"syntax-title\"u003ePreviewProvideru003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003estaticu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e previews: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eCLKComplicationTemplateGraphicRectangularFullViewu003c/spanu003e(u003cspan class=\"syntax-type\"u003eGaugeSampleu003c/spanu003e())\n .previewContext()\n }\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10048/4/A4A61EDD-9948-4DB8-98BB-8BA633D211CC/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10048/4/A4A61EDD-9948-4DB8-98BB-8BA633D211CC/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10048/4/A4A61EDD-9948-4DB8-98BB-8BA633D211CC/transcripts/wwdc2020-10048-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10048/4/A4A61EDD-9948-4DB8-98BB-8BA633D211CC/wwdc2020_10048_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10048/4/A4A61EDD-9948-4DB8-98BB-8BA633D211CC/wwdc2020_10048_sd.mp4",
"duration": 1372
},
"related": {
"activities": [
"wwdc2020-10041",
"wwdc2020-10046",
"wwdc2020-10049",
"wwdc2020-10100",
"wwdc2020-10771",
"wwdc2020-10772"
],
"resources": [
969,
968,
882,
572,
5
]
}
},
{
"id": "wwdc2020-10081",
"staticContentId": 3831,
"eventContentId": 10081,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10081",
"description": "Quickly detect power and performance regressions and troubleshoot app issues when you adopt MetricKit. Discover the latest trackable metrics for your app, including CPU instructions, animation hitches, and exit reasons. And learn about diagnostics in MetricKit that can help you troubleshoot hangs, crashes, and disk writes.",
"title": "What's new in MetricKit",
"originalPublishingDate": "2020-06-26T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS"
],
"topicIds": [
35,
33
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Using MetricKit",
"startTimeSeconds": 131,
"endTimeSeconds": 174,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e MetricKit\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eMySubscriberu003c/spanu003e: u003cspan class=\"syntax-title\"u003eNSObjectu003c/spanu003e, u003cspan class=\"syntax-title\"u003eMXMetricManagerSubscriberu003c/spanu003e u003c/spanu003e{\n \n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e metricManager: u003cspan class=\"syntax-type\"u003eMXMetricManager?u003c/spanu003e\n \n u003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-keyword\"u003einitu003c/spanu003e() {\n u003cspan class=\"syntax-keyword\"u003esuperu003c/spanu003e.u003cspan class=\"syntax-keyword\"u003einitu003c/spanu003e()\n metricManager = u003cspan class=\"syntax-type\"u003eMXMetricManageru003c/spanu003e.shared\n metricManager?.add(u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e)\n }\n \n u003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-keyword\"u003edeinitu003c/spanu003e() {\n metricManager?.remove(u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e)\n }\n \n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003edidReceiveu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e payload: [MXMetricPayload])u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e metricPayload u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e payload {\n u003cspan class=\"syntax-comment\"u003e// Do something with metricPayload.u003c/spanu003e\n }\n }\n \n}"
},
{
"title": "Adopting MetricKit Diagnostics",
"startTimeSeconds": 494,
"endTimeSeconds": 509,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003edidReceiveu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e payload: [MXDiagnosticPayload])u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e diagnosticPayload u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e payload {\n u003cspan class=\"syntax-comment\"u003e// Consume diagnosticPayload.u003c/spanu003e\n }\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10081/3/7AC69CDE-C614-4237-9C10-93A3B67C923E/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10081/3/7AC69CDE-C614-4237-9C10-93A3B67C923E/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10081/3/7AC69CDE-C614-4237-9C10-93A3B67C923E/transcripts/wwdc2020-10081-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10081/3/7AC69CDE-C614-4237-9C10-93A3B67C923E/wwdc2020_10081_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10081/3/7AC69CDE-C614-4237-9C10-93A3B67C923E/wwdc2020_10081_sd.mp4",
"duration": 825
},
"related": {
"activities": [
"wwdc2020-10057",
"wwdc2020-10076",
"wwdc2020-10077",
"wwdc2020-10078",
"wwdc2020-10845",
"wwdc2020-10893",
"wwdc2020-10894"
],
"resources": [
1321,
1320
]
}
},
{
"id": "wwdc2020-10676",
"staticContentId": 3568,
"eventContentId": 10676,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10676",
"description": "Privacy is a more important issue than ever. Learn about Apple’s privacy pillars, our approach to privacy, and how to adopt the latest features on our platforms that can help you earn customer trust, create more personal experiences, and improve engagement. Explore the transparency iOS provides when your app is recording using the microphone or camera, control over location with approximate location, tracking transparency and permissions, and much more.",
"title": "Build trust through better privacy",
"originalPublishingDate": "2020-06-23T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS"
],
"keywords": [
"ad network",
"approximate location",
"autofill",
"camera",
"contacts",
"data minimazation",
"dns encryption",
"idfa",
"location",
"mac address",
"microphone",
"permissions",
"photos library",
"picker",
"privacy",
"privacy control",
"private network",
"tracking",
"transparency",
"trust"
],
"topicIds": [
19
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10676/3/3D9FA124-32D0-48C4-8232-64426A430A56/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10676/3/3D9FA124-32D0-48C4-8232-64426A430A56/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10676/3/3D9FA124-32D0-48C4-8232-64426A430A56/transcripts/wwdc2020-10676-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10676/3/3D9FA124-32D0-48C4-8232-64426A430A56/wwdc2020_10676_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10676/3/3D9FA124-32D0-48C4-8232-64426A430A56/wwdc2020_10676_sd.mp4",
"duration": 2164
},
"related": {
"activities": [
"wwdc2020-10047",
"wwdc2020-10110",
"wwdc2020-10115",
"wwdc2020-10120",
"wwdc2020-10152",
"wwdc2020-10159",
"wwdc2020-10162",
"wwdc2020-10172",
"wwdc2020-10189",
"wwdc2020-10641",
"wwdc2020-10652",
"wwdc2020-10660",
"wwdc2020-10661",
"wwdc2020-10665",
"wwdc2020-10668",
"wwdc2020-10795",
"wwdc2020-10796"
],
"resources": [
1341,
1340
]
}
},
{
"id": "wwdc2020-10605",
"staticContentId": 3874,
"eventContentId": 10605,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10605",
"description": "Learn how to locate graphics issues in minutes with Metal’s debugging and performance optimization tools in Xcode 12. We’ll show you how to diagnose problems quickly using Metal Debugger. Discover the new summary view, which suggests ways to improve memory usage, bandwidth, performance, and implementation of the Metal API.\r\n\r\nYou should have a basic understanding of Metal to get the most out of this session. For background, watch “Harness Apple GPUs with Metal.”",
"title": "Gain insights into your Metal app with Xcode 12",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS"
],
"topicIds": [
38,
33,
27,
26,
25
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10605/5/DF0941E7-C0BC-41CD-AFEB-03940FC455E6/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10605/5/DF0941E7-C0BC-41CD-AFEB-03940FC455E6/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10605/4/FC63E0EE-98A8-4F37-A64F-889480F1D68B/transcripts/wwdc2020-10605-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10605/5/DF0941E7-C0BC-41CD-AFEB-03940FC455E6/wwdc2020_10605_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10605/5/DF0941E7-C0BC-41CD-AFEB-03940FC455E6/wwdc2020_10605_sd.mp4",
"duration": 857
},
"related": {
"activities": [
"wwdc2020-10602",
"wwdc2020-10603",
"wwdc2020-10616",
"wwdc2020-10631",
"wwdc2020-10810",
"wwdc2020-10811",
"wwdc2020-10812",
"wwdc2020-10813",
"wwdc2020-10814",
"wwdc2020-10815",
"wwdc2020-10816",
"wwdc2020-10817",
"wwdc2019-606",
"wwdc2018-608"
],
"resources": [
1331,
1330,
38
]
}
},
{
"id": "wwdc2020-10073",
"staticContentId": 3510,
"eventContentId": 10073,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10073",
"description": "When you create an intent for your app, you can help people accomplish tasks quickly by using it as part of a shortcut or when asking Siri. Learn how to adopt Siri more easily than ever when you use SiriKit’s in-app intent handling, and how to improve Siri performance with existing Intents app extensions. We'll also show you how to leverage features in SiriKit to improve the experience of using your actions — like including images and subtitles for a rich conversational experience. And find out how to fine tune support for intents in your codebase to make your life as a developer easier.",
"title": "Empower your intents",
"originalPublishingDate": "2020-06-26T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"tvOS",
"watchOS"
],
"keywords": [
"conversational interaction",
"extensions",
"in-app intent handling",
"intents",
"intentsui",
"shortcuts",
"siri",
"sirikit",
"voice"
],
"topicIds": [
21,
13
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10073/3/AA5FAD47-6829-4827-8B36-DB2F30DFC267/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10073/3/AA5FAD47-6829-4827-8B36-DB2F30DFC267/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10073/3/AA5FAD47-6829-4827-8B36-DB2F30DFC267/transcripts/wwdc2020-10073-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10073/3/AA5FAD47-6829-4827-8B36-DB2F30DFC267/wwdc2020_10073_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10073/3/AA5FAD47-6829-4827-8B36-DB2F30DFC267/wwdc2020_10073_sd.mp4",
"duration": 1219
},
"related": {
"activities": [
"wwdc2020-10053",
"wwdc2020-10060",
"wwdc2020-10061",
"wwdc2020-10068",
"wwdc2020-10071",
"wwdc2020-10074",
"wwdc2020-10083",
"wwdc2020-10084",
"wwdc2020-10086",
"wwdc2020-10088",
"wwdc2020-10190",
"wwdc2020-10200",
"wwdc2020-10203",
"wwdc2020-10839",
"wwdc2020-10877",
"wwdc2020-10878",
"wwdc2020-10914",
"wwdc2020-10917",
"wwdc2020-10963"
],
"resources": [
1107,
1106,
893,
350
]
}
},
{
"id": "wwdc2020-10006",
"staticContentId": 3389,
"eventContentId": 10006,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10006",
"description": "You can now store car keys on iPhone or Apple Watch. You no longer have to bring your key fob to unlock and start your car. And with digital keys, it's easy to share them with family or friends, and manage keys remotely.\r\n\r\nThis session is intended for automakers who want to adopt digital car keys in their vehicles. We'll talk about the core feature set including owner pairing, transactions (when you unlock or start your car), key sharing, and key management. Learn about the car key architecture and how it ensures security and privacy. Get information on where to go next for information on hardware and specifications.",
"title": "Introducing Car Keys",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"watchOS"
],
"keywords": [
"🔑",
"🚗",
"🚙",
"car",
"nfc",
"u1",
"ultra wideband",
"uwb"
],
"topicIds": [
10,
19
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10006/2/9AEBCF31-6D56-4432-AD25-F0BD213AFA55/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10006/2/9AEBCF31-6D56-4432-AD25-F0BD213AFA55/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10006/2/9AEBCF31-6D56-4432-AD25-F0BD213AFA55/transcripts/wwdc2020-10006-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10006/2/9AEBCF31-6D56-4432-AD25-F0BD213AFA55/wwdc2020_10006_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10006/2/9AEBCF31-6D56-4432-AD25-F0BD213AFA55/wwdc2020_10006_sd.mp4",
"duration": 1292
},
"related": {
"activities": [
"wwdc2020-10693"
],
"resources": [
977,
976
]
}
},
{
"id": "wwdc2020-10153",
"staticContentId": 3436,
"eventContentId": 10153,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10153",
"description": "With Core ML you can bring incredible machine learning models to your app and run them entirely on-device. And when you use Core ML Converters, you can incorporate almost any trained model from TensorFlow or PyTorch and take full advantage of the GPU, CPU, and Neural Engine. Discover everything you need to begin converting existing models from other ML platforms and explore how to create custom operations that extend the capabilities of your models.\r\n\r\nOnce you’ve converted a model to Core ML, learn more about deployment strategy for those models by watching “Use model deployment and security with Core ML.”",
"title": "Get models on device using Core ML Converters",
"originalPublishingDate": "2020-06-26T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"keywords": [
"ai",
"artificial intelligence",
"converters",
"core ml",
"core ml converters",
"core ml tools",
"custom operations",
"deep learning",
"learning",
"machine learning",
"mil",
"model",
"natural language",
"neural network",
"python",
"tensorflow",
"training"
],
"topicIds": [
16
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "TensorFlow conversion using tfcoreml",
"startTimeSeconds": 178,
"endTimeSeconds": 192,
"language": "python",
"code": "u003cspan class=\"syntax-comment\"u003e# pip install tfcoremlu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e# pip install coremltoolsu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e tfcoreml\nmlmodel = tfcoreml.convert(tf_model, mlmodel_path=u003cspan class=\"syntax-string\"u003e\"/tmp/model.mlmodel\"u003c/spanu003e)"
},
{
"title": "New TensorFlow model conversion",
"startTimeSeconds": 196,
"endTimeSeconds": 202,
"language": "python",
"code": "u003cspan class=\"syntax-comment\"u003e# pip install coremltoolsu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e coremltools u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e ct\nmlmodel = ct.convert(tf_model)"
},
{
"title": "ONNX conversion to Core ML",
"startTimeSeconds": 237,
"endTimeSeconds": 263,
"language": "python",
"code": "u003cspan class=\"syntax-comment\"u003e# pip install onnx-coremlu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e# pip install coremltoolsu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e onnx_coreml\nonnx_model = torch.export(torch_model)\nmlmodel = onnx_coreml.convert(onnx_model)"
},
{
"title": "New PyTorch model conversion",
"startTimeSeconds": 268,
"endTimeSeconds": 286,
"language": "python",
"code": "u003cspan class=\"syntax-comment\"u003e# pip install coremltoolsu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e coremltools u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e ct \nmlmodel = ct.convert(torch_script_model)"
},
{
"title": "Unified conversion API",
"startTimeSeconds": 292,
"endTimeSeconds": 323,
"language": "python",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e coremltools u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e ct\n\nmodel = ct.convert(\n source_model u003cspan class=\"syntax-comment\"u003e# TF1, TF2, or PyTorch modelu003c/spanu003e\n)"
},
{
"title": "Demo 1: TF2 conversion",
"startTimeSeconds": 402,
"endTimeSeconds": 451,
"language": "python",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e coremltools u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e ct \nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e tensorflow u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e tf\n\ntf_model = tf.keras.applications.MobileNet()\nmlmodel = ct.convert(tf_model)"
},
{
"title": "Demo 1: Pytorch conversion",
"startTimeSeconds": 461,
"endTimeSeconds": 630,
"language": "python",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e coremltools u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e ct \nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e torch\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e torchvision \n\ntorch_model = torchvision.models.mobilenet_v2()\n\ntorch_model.eval()\nexample_input = torch.rand(u003cspan class=\"syntax-number\"u003e1u003c/spanu003e, u003cspan class=\"syntax-number\"u003e3u003c/spanu003e, u003cspan class=\"syntax-number\"u003e256u003c/spanu003e, u003cspan class=\"syntax-number\"u003e256u003c/spanu003e)\ntraced_model = torch.jit.trace(torch_model, example_input)\n\nmlmodel = ct.convert(traced_model,\n inputs=[ct.TensorType(shape=example_input.shape)])\n\nprint(mlmodel)\n\nspec = mlmodel.get_spec()\nct.utils.rename_feature(spec, u003cspan class=\"syntax-string\"u003e\"input.1\"u003c/spanu003e, u003cspan class=\"syntax-string\"u003e\"myInputName\"u003c/spanu003e)\nct.utils.rename_feature(spec, u003cspan class=\"syntax-string\"u003e\"1648\"u003c/spanu003e, u003cspan class=\"syntax-string\"u003e\"myOutputName\"u003c/spanu003e)\nmlmodel = ct.models.MLModel(spec)\n\nprint(mlmodel)"
},
{
"title": "Demo 1 : TF1 conversion",
"startTimeSeconds": 637,
"endTimeSeconds": 767,
"language": "python",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e coremltools u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e ct \nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e tensorflow u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e tf\n\nmlmodel = ct.convert(u003cspan class=\"syntax-string\"u003e\"mobilenet_frozen_graph.pb\"u003c/spanu003e,\n inputs=[ct.ImageType(bias=[u003cspan class=\"syntax-number\"u003e-1u003c/spanu003e,u003cspan class=\"syntax-number\"u003e-1u003c/spanu003e,u003cspan class=\"syntax-number\"u003e-1u003c/spanu003e], scale=u003cspan class=\"syntax-number\"u003e1u003c/spanu003e/u003cspan class=\"syntax-number\"u003e127.0u003c/spanu003e)],\n classifier_config=ct.ClassifierConfig(u003cspan class=\"syntax-string\"u003e\"labels.txt\"u003c/spanu003e))\n\nmlmodel.short_description = u003cspan class=\"syntax-string\"u003e'An image classifier'u003c/spanu003e\nmlmodel.license = u003cspan class=\"syntax-string\"u003e'Apache 2.0'u003c/spanu003e\nmlmodel.author = u003cspan class=\"syntax-string\"u003e\"Original Paper: A. Howard, M. Zhu, B. Chen, D. Kalenichenko, W. Wang, \"u003c/spanu003e\\\n u003cspan class=\"syntax-string\"u003e\"T. Weyand, M. Andreetto, H. Adam\"u003c/spanu003e\n\nmlmodel.save(u003cspan class=\"syntax-string\"u003e\"mobilenet.mlmodel\"u003c/spanu003e)"
},
{
"title": "Demo 1 Recap: Using coremltools convert",
"startTimeSeconds": 813,
"endTimeSeconds": 824,
"language": "python",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e coremltools u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e ct\nmlmodel = ct.convert(u003cspan class=\"syntax-string\"u003e\"./tf1_inception_model.pb\"u003c/spanu003e)\nmlmodel = ct.convert(u003cspan class=\"syntax-string\"u003e\"./tf2_inception_model.h5\"u003c/spanu003e)\nmlmodel = ct.convert(torch_model, inputs=[ct.TensorType(shape=example_input.shape)])"
},
{
"title": "Converting a Deep Speech model",
"startTimeSeconds": 945,
"endTimeSeconds": 1283,
"language": "python",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e numpy u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e np\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e IPython.display u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e ipd\n\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e coremltools u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e ct\n\nu003cspan class=\"syntax-comment\"u003e### Pretrained models and chekpoints are available on the repository: u003c/spanu003e\nhttps://github.com/mozilla/DeepSpeech\n\n!python DeepSpeech.py --export_dir /tmp --checkpoint_dir ./deepspeechu003cspan class=\"syntax-number\"u003e-0.7u003c/spanu003eu003cspan class=\"syntax-number\"u003e.1u003c/spanu003e-checkpoint --alphabet_config_path=alphabet.txt --scorer_path=kenlm.scorer u0026gt;/dev/null u003cspan class=\"syntax-number\"u003e2u003c/spanu003eu0026gt;u0026amp;u003cspan class=\"syntax-number\"u003e1u003c/spanu003e\n\nls /tmp/*.pb\n\ntf_model = u003cspan class=\"syntax-string\"u003e\"/tmp/output_graph.pb\"u003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003efromu003c/spanu003e demo_utils u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e inspect_tf_outputs\n\ninspect_tf_outputs(tf_model)\n\noutputs = [u003cspan class=\"syntax-string\"u003e\"logits\"u003c/spanu003e, u003cspan class=\"syntax-string\"u003e\"new_state_c\"u003c/spanu003e, u003cspan class=\"syntax-string\"u003e\"new_state_h\"u003c/spanu003e]\n\nmlmodel = ct.convert(tf_model, outputs=outputs)\n\naudiofile = u003cspan class=\"syntax-string\"u003e\"./audio_sample_16bit_mono_16khz.wav\"u003c/spanu003e\n\nipd.Audio(audiofile) \n\nu003cspan class=\"syntax-keyword\"u003efromu003c/spanu003e demo_utils u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e preprocessing, postprocessing\n\nmfccs = preprocessing(audiofile)\n\nmfccs.shape\n\nu003cspan class=\"syntax-keyword\"u003efromu003c/spanu003e demo_utils u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e inspect_inputs\n\ninspect_inputs(mlmodel, tf_model)\n\nstart = u003cspan class=\"syntax-number\"u003e0u003c/spanu003e \nstep = u003cspan class=\"syntax-number\"u003e16u003c/spanu003e\n\nmax_time_steps = mfccs.shape[u003cspan class=\"syntax-number\"u003e1u003c/spanu003e]\n\nlogits_sequence = []\n\ninput_dict = {}\n\ninput_dict[u003cspan class=\"syntax-string\"u003e\"input_lengths\"u003c/spanu003e] = np.array([step]).astype(np.float32)\n\ninput_dict[u003cspan class=\"syntax-string\"u003e\"previous_state_c\"u003c/spanu003e] = np.zeros([u003cspan class=\"syntax-number\"u003e1u003c/spanu003e, u003cspan class=\"syntax-number\"u003e2048u003c/spanu003e]).astype(np.float32) u003cspan class=\"syntax-comment\"u003e# Initializing cell state u003c/spanu003e\ninput_dict[u003cspan class=\"syntax-string\"u003e\"previous_state_h\"u003c/spanu003e] = np.zeros([u003cspan class=\"syntax-number\"u003e1u003c/spanu003e, u003cspan class=\"syntax-number\"u003e2048u003c/spanu003e]).astype(np.float32) u003cspan class=\"syntax-comment\"u003e# Initializing hidden state u003c/spanu003e\n\n\nprint(u003cspan class=\"syntax-string\"u003e\"Transcription: \\n\"u003c/spanu003e)\n\nu003cspan class=\"syntax-keyword\"u003ewhileu003c/spanu003e (start + step) u0026lt; max_time_steps:\n input_dict[u003cspan class=\"syntax-string\"u003e\"input_node\"u003c/spanu003e] = mfccs[:, start:(start + step), :, :]\n \n u003cspan class=\"syntax-comment\"u003e# Evaluationu003c/spanu003e\n preds = mlmodel.predict(input_dict)\n \n \n start += step\n logits_sequence.append(preds[u003cspan class=\"syntax-string\"u003e\"logits\"u003c/spanu003e])\n\n \n u003cspan class=\"syntax-comment\"u003e# Updating statesu003c/spanu003e\n input_dict[u003cspan class=\"syntax-string\"u003e\"previous_state_c\"u003c/spanu003e] = preds[u003cspan class=\"syntax-string\"u003e\"new_state_c\"u003c/spanu003e]\n input_dict[u003cspan class=\"syntax-string\"u003e\"previous_state_h\"u003c/spanu003e] = preds[u003cspan class=\"syntax-string\"u003e\"new_state_h\"u003c/spanu003e]\n \n \n u003cspan class=\"syntax-comment\"u003e# Decodingu003c/spanu003e\n probs = np.concatenate(logits_sequence)\n transcription = postprocessing(probs)\n print(transcription[u003cspan class=\"syntax-number\"u003e0u003c/spanu003e][u003cspan class=\"syntax-number\"u003e1u003c/spanu003e], end=u003cspan class=\"syntax-string\"u003e\"\\r\"u003c/spanu003e, flush=u003cspan class=\"syntax-literal\"u003eTrueu003c/spanu003e)\n\n!python DeepSpeech.py --n_steps u003cspan class=\"syntax-number\"u003e-1u003c/spanu003e --export_dir /tmp --checkpoint_dir ./deepspeechu003cspan class=\"syntax-number\"u003e-0.7u003c/spanu003eu003cspan class=\"syntax-number\"u003e.1u003c/spanu003e-checkpoint --alphabet_config_path=alphabet.txt --scorer_path=kenlm.scorer u0026gt;/dev/null u003cspan class=\"syntax-number\"u003e2u003c/spanu003eu0026gt;u0026amp;u003cspan class=\"syntax-number\"u003e1u003c/spanu003e\n\nmlmodel = ct.convert(tf_model, outputs=outputs)\n\ninspect_inputs(mlmodel,tf_model)\n\ninput_dict = {}\n\ninput_dict[u003cspan class=\"syntax-string\"u003e\"input_node\"u003c/spanu003e] = mfccs\n\ninput_dict[u003cspan class=\"syntax-string\"u003e\"input_lengths\"u003c/spanu003e] = np.array([mfccs.shape[u003cspan class=\"syntax-number\"u003e1u003c/spanu003e]]).astype(np.float32)\ninput_dict[u003cspan class=\"syntax-string\"u003e\"previous_state_c\"u003c/spanu003e] = np.zeros([u003cspan class=\"syntax-number\"u003e1u003c/spanu003e, u003cspan class=\"syntax-number\"u003e2048u003c/spanu003e]).astype(np.float32) u003cspan class=\"syntax-comment\"u003e# Initializing cell state u003c/spanu003e\ninput_dict[u003cspan class=\"syntax-string\"u003e\"previous_state_h\"u003c/spanu003e] = np.zeros([u003cspan class=\"syntax-number\"u003e1u003c/spanu003e, u003cspan class=\"syntax-number\"u003e2048u003c/spanu003e]).astype(np.float32) u003cspan class=\"syntax-comment\"u003e# Initializing hidden state u003c/spanu003e\n\nprobs = mlmodel.predict(input_dict)[u003cspan class=\"syntax-string\"u003e\"logits\"u003c/spanu003e]\n\ntranscription = postprocessing(probs)\n\nprint(transcription[u003cspan class=\"syntax-number\"u003e0u003c/spanu003e][u003cspan class=\"syntax-number\"u003e1u003c/spanu003e])"
},
{
"title": "Deep Speech Demo Recap: Convert with input type",
"startTimeSeconds": 1312,
"endTimeSeconds": 1355,
"language": "python",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e coremltools u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e ct\n\ninput = ct.TensorType(name=u003cspan class=\"syntax-string\"u003e\"input_node\"u003c/spanu003e, shape=(u003cspan class=\"syntax-number\"u003e1u003c/spanu003e, u003cspan class=\"syntax-number\"u003e16u003c/spanu003e, u003cspan class=\"syntax-number\"u003e19u003c/spanu003e, u003cspan class=\"syntax-number\"u003e26u003c/spanu003e))\nmodel = ct.convert(tf_model, outputs=outputs, inputs=[input])"
},
{
"title": "MIL Builder API sample",
"startTimeSeconds": 1586,
"endTimeSeconds": 1660,
"language": "python",
"code": "u003cspan class=\"syntax-keyword\"u003efromu003c/spanu003e coremltools.converters.mil u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e Builder u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e mb\n\nu003cspan class=\"syntax-meta\"u003e@mb.program(input_specs=[mb.TensorSpec(shape=(1, 100, 100, 3))])u003c/spanu003e\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003edefu003c/spanu003e u003cspan class=\"syntax-title\"u003eprogu003c/spanu003eu003cspan class=\"syntax-params\"u003e(x)u003c/spanu003e:u003c/spanu003e\n x = mb.relu(x=x)\n x = mb.transpose(x=x, perm=[u003cspan class=\"syntax-number\"u003e0u003c/spanu003e, u003cspan class=\"syntax-number\"u003e3u003c/spanu003e, u003cspan class=\"syntax-number\"u003e1u003c/spanu003e, u003cspan class=\"syntax-number\"u003e2u003c/spanu003e])\n x = mb.reduce_mean(x=x, axes=[u003cspan class=\"syntax-number\"u003e2u003c/spanu003e, u003cspan class=\"syntax-number\"u003e3u003c/spanu003e], keep_dims=u003cspan class=\"syntax-literal\"u003eFalseu003c/spanu003e)\n x = mb.log(x=x)\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e x"
},
{
"title": "Converting with composite ops",
"startTimeSeconds": 1700,
"endTimeSeconds": 1789,
"language": "python",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e coremltools u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e ct\n\nu003cspan class=\"syntax-keyword\"u003efromu003c/spanu003e transformers u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e TFT5Model\n\nmodel = TFT5Model.from_pretrained(u003cspan class=\"syntax-string\"u003e't5-small'u003c/spanu003e)\n\nmlmodel = ct.convert(model)\n\nu003cspan class=\"syntax-comment\"u003e# Einsum Notationu003c/spanu003e\n\n $$ \\Large u003cspan class=\"syntax-string\"u003e\"bnqd,bnkd \\rightarrow bnqk\"u003c/spanu003e $$\n\n$$ \\large C(b, n, q, k) = \\sum_d A(b, n, q, d) \\times B(b, n, k, d) $$\n\n$$ \\Large C = AB^{T}$$\n\nu003cspan class=\"syntax-keyword\"u003efromu003c/spanu003e coremltools.converters.mil u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e Builder u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e mb\n\nu003cspan class=\"syntax-keyword\"u003efromu003c/spanu003e coremltools.converters.mil u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e register_tf_op\n\nu003cspan class=\"syntax-meta\"u003e@register_tf_opu003c/spanu003e\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003edefu003c/spanu003e u003cspan class=\"syntax-title\"u003eEinsumu003c/spanu003eu003cspan class=\"syntax-params\"u003e(context, node)u003c/spanu003e:u003c/spanu003e\n\n\t\tu003cspan class=\"syntax-keyword\"u003eassertu003c/spanu003e node.attr[u003cspan class=\"syntax-string\"u003e'equation'u003c/spanu003e] == u003cspan class=\"syntax-string\"u003e'bnqd,bnkd-u0026gt;bnqk'u003c/spanu003e\n\n a = context[node.inputs[u003cspan class=\"syntax-number\"u003e0u003c/spanu003e]]\n b = context[node.inputs[u003cspan class=\"syntax-number\"u003e1u003c/spanu003e]]\n\n x = mb.matmul(x=a, y=b, transpose_x=u003cspan class=\"syntax-literal\"u003eFalseu003c/spanu003e, transpose_y=u003cspan class=\"syntax-literal\"u003eTrueu003c/spanu003e, name=node.name)\n\n context.add(node.name, x)\n\nmlmodel = ct.convert(model)\n\nprint(mlmodel)"
},
{
"title": "Recap: Custom operation",
"startTimeSeconds": 1790,
"endTimeSeconds": 1820,
"language": "python",
"code": "u003cspan class=\"syntax-meta\"u003e@register_tf_opu003c/spanu003e\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003edefu003c/spanu003e u003cspan class=\"syntax-title\"u003eEinsumu003c/spanu003eu003cspan class=\"syntax-params\"u003e(context, node)u003c/spanu003e:u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eassertu003c/spanu003e node.attr[u003cspan class=\"syntax-string\"u003e'equation'u003c/spanu003e] == u003cspan class=\"syntax-string\"u003e'bnqd,bnkd-u0026gt;bnqk'u003c/spanu003e\n\n a = context[node.inputs[u003cspan class=\"syntax-number\"u003e0u003c/spanu003e]]\n b = context[node.inputs[u003cspan class=\"syntax-number\"u003e1u003c/spanu003e]]\n\n x = mb.matmul(x=a, y=b, transpose_x=u003cspan class=\"syntax-literal\"u003eFalseu003c/spanu003e, transpose_y=u003cspan class=\"syntax-literal\"u003eTrueu003c/spanu003e, name=node.name)\n \n context.add(node.name, x)"
},
{
"title": "Deep Speech demo utilities",
"startTimeSeconds": 1790,
"endTimeSeconds": 1890,
"language": "python",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e numpy u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e np\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e pandas u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e pd\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e tensorflow u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e tf\nu003cspan class=\"syntax-keyword\"u003efromu003c/spanu003e tensorflow.python.ops u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e gen_audio_ops u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e contrib_audio\n\n\nu003cspan class=\"syntax-keyword\"u003efromu003c/spanu003e deepspeech_training.util.text u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e Alphabet\nu003cspan class=\"syntax-keyword\"u003efromu003c/spanu003e ds_ctcdecoder u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e ctc_beam_search_decoder, Scorer\n\n\nu003cspan class=\"syntax-comment\"u003e## Preprocessing + Postprocessing functions are constructed using code in DeepSpeech repository: https://github.com/mozilla/DeepSpeechu003c/spanu003e\n\naudio_window_samples = u003cspan class=\"syntax-number\"u003e512u003c/spanu003e\naudio_step_samples = u003cspan class=\"syntax-number\"u003e320u003c/spanu003e\nn_input = u003cspan class=\"syntax-number\"u003e26u003c/spanu003e\naudio_sample_rate = u003cspan class=\"syntax-number\"u003e16000u003c/spanu003e\ncontext = u003cspan class=\"syntax-number\"u003e9u003c/spanu003e\n\nlm_alpha = u003cspan class=\"syntax-number\"u003e0.931289039105002u003c/spanu003e\nlm_beta = u003cspan class=\"syntax-number\"u003e1.1834137581510284u003c/spanu003e\nscorer_path = u003cspan class=\"syntax-string\"u003e\"./kenlm.scorer\"u003c/spanu003e\n\nbeam_width = u003cspan class=\"syntax-number\"u003e1024u003c/spanu003e\ncutoff_prob = u003cspan class=\"syntax-number\"u003e1.0u003c/spanu003e\ncutoff_top_n = u003cspan class=\"syntax-number\"u003e300u003c/spanu003e\n\nalphabet = Alphabet(u003cspan class=\"syntax-string\"u003e\"./alphabet.txt\"u003c/spanu003e)\n\nscorer = Scorer(lm_alpha, lm_beta, scorer_path, alphabet)\n\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003edefu003c/spanu003e u003cspan class=\"syntax-title\"u003eaudiofile_to_featuresu003c/spanu003eu003cspan class=\"syntax-params\"u003e(wav_filename)u003c/spanu003e:u003c/spanu003e\n \n samples = tf.io.read_file(wav_filename)\n \n decoded = contrib_audio.decode_wav(samples, desired_channels=u003cspan class=\"syntax-number\"u003e1u003c/spanu003e)\n \n spectrogram = contrib_audio.audio_spectrogram(decoded.audio,\n window_size=audio_window_samples,\n stride=audio_step_samples,\n magnitude_squared=u003cspan class=\"syntax-literal\"u003eTrueu003c/spanu003e)\n \n mfccs = contrib_audio.mfcc(spectrogram = spectrogram,\n sample_rate = decoded.sample_rate,\n dct_coefficient_count=n_input,\n upper_frequency_limit=audio_sample_rate/u003cspan class=\"syntax-number\"u003e2u003c/spanu003e)\n \n mfccs = tf.reshape(mfccs, [u003cspan class=\"syntax-number\"u003e-1u003c/spanu003e, n_input])\n\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e mfccs, tf.shape(input=mfccs)[u003cspan class=\"syntax-number\"u003e0u003c/spanu003e]\n\n\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003edefu003c/spanu003e u003cspan class=\"syntax-title\"u003ecreate_overlapping_windowsu003c/spanu003eu003cspan class=\"syntax-params\"u003e(batch_x)u003c/spanu003e:u003c/spanu003e\n \n batch_size = tf.shape(input=batch_x)[u003cspan class=\"syntax-number\"u003e0u003c/spanu003e]\n window_width = u003cspan class=\"syntax-number\"u003e2u003c/spanu003e * context + u003cspan class=\"syntax-number\"u003e1u003c/spanu003e\n num_channels = n_input\n\n eye_filter = tf.constant(np.eye(window_width * num_channels)\n .reshape(window_width, num_channels, window_width * num_channels), tf.float32) \n \n u003cspan class=\"syntax-comment\"u003e# Create overlapping windowsu003c/spanu003e\n batch_x = tf.nn.conv1d(input=batch_x, filters=eye_filter, stride=u003cspan class=\"syntax-number\"u003e1u003c/spanu003e, padding=u003cspan class=\"syntax-string\"u003e'SAME'u003c/spanu003e)\n\n batch_x = tf.reshape(batch_x, [batch_size, u003cspan class=\"syntax-number\"u003e-1u003c/spanu003e, window_width, num_channels])\n\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e batch_x\n\n\nsess = tf.Session(graph=tf.Graph())\n\nu003cspan class=\"syntax-keyword\"u003ewithu003c/spanu003e sess.graph.as_default() u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e g:\n path = tf.placeholder(tf.string)\n _features, _ = audiofile_to_features(path)\n _features = tf.expand_dims(_features, u003cspan class=\"syntax-number\"u003e0u003c/spanu003e)\n _features = create_overlapping_windows(_features)\n\n \n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003edefu003c/spanu003e u003cspan class=\"syntax-title\"u003epreprocessingu003c/spanu003eu003cspan class=\"syntax-params\"u003e(input_file_path)u003c/spanu003e:u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e _features.eval(session=sess, feed_dict={path: input_file_path})\n\n\n\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003edefu003c/spanu003e u003cspan class=\"syntax-title\"u003epostprocessingu003c/spanu003eu003cspan class=\"syntax-params\"u003e(logits)u003c/spanu003e:u003c/spanu003e\n logits = np.squeeze(logits)\n\n decoded = ctc_beam_search_decoder(logits, alphabet, beam_width,\n scorer=scorer, cutoff_prob=cutoff_prob,\n cutoff_top_n=cutoff_top_n)\n\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e decoded\n\n\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003edefu003c/spanu003e u003cspan class=\"syntax-title\"u003einspect_tf_outputsu003c/spanu003eu003cspan class=\"syntax-params\"u003e(path)u003c/spanu003e:u003c/spanu003e\n \n u003cspan class=\"syntax-keyword\"u003ewithu003c/spanu003e open(path, u003cspan class=\"syntax-string\"u003e'rb'u003c/spanu003e) u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e f:\n serialized = f.read()\n gdef = tf.GraphDef()\n gdef.ParseFromString(serialized)\n\n u003cspan class=\"syntax-keyword\"u003ewithu003c/spanu003e tf.Graph().as_default() u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e g:\n tf.import_graph_def(gdef, name=u003cspan class=\"syntax-string\"u003e\"\"u003c/spanu003e)\n\n output_nodes = []\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e op u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e g.get_operations():\n \n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e op.type == u003cspan class=\"syntax-string\"u003e\"Const\"u003c/spanu003e:\n u003cspan class=\"syntax-keyword\"u003econtinueu003c/spanu003e\n \n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e all([len(g.get_tensor_by_name(tensor.name).consumers()) == u003cspan class=\"syntax-number\"u003e0u003c/spanu003e u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e tensor u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e op.outputs]):\n \n output_nodes.append(op.name)\n\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e output_nodes\n\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003edefu003c/spanu003e u003cspan class=\"syntax-title\"u003einspect_inputsu003c/spanu003eu003cspan class=\"syntax-params\"u003e(mlmodel, tfmodel)u003c/spanu003e:u003c/spanu003e\n \n names = []\n ranks = []\n shapes = []\n\n spec = mlmodel.get_spec()\n\n u003cspan class=\"syntax-keyword\"u003ewithu003c/spanu003e open(tfmodel, u003cspan class=\"syntax-string\"u003e'rb'u003c/spanu003e) u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e f:\n serialized = f.read()\n gdef = tf.GraphDef()\n gdef.ParseFromString(serialized)\n\n u003cspan class=\"syntax-keyword\"u003ewithu003c/spanu003e tf.Graph().as_default() u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e g:\n tf.import_graph_def(gdef, name=u003cspan class=\"syntax-string\"u003e\"\"u003c/spanu003e)\n\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e tensor u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e spec.description.input:\n name = tensor.name\n shape = tensor.type.multiArrayType.shape\n\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e tensor.type.multiArrayType.shapeRange:\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e dim, size u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e enumerate(tensor.type.multiArrayType.shapeRange.sizeRanges):\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e size.upperBound == u003cspan class=\"syntax-number\"u003e-1u003c/spanu003e:\n shape[dim] = u003cspan class=\"syntax-number\"u003e-1u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eelifu003c/spanu003e size.lowerBound u0026lt; size.upperBound:\n shape[dim] = u003cspan class=\"syntax-number\"u003e-1u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eelifu003c/spanu003e size.lowerBound == size.upperBound:\n u003cspan class=\"syntax-keyword\"u003eassertu003c/spanu003e shape[dim] == size.lowerBound\n u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e:\n u003cspan class=\"syntax-keyword\"u003eraiseu003c/spanu003e TypeError(u003cspan class=\"syntax-string\"u003e\"Invalid shape range\"u003c/spanu003e)\n\n coreml_shape = tuple(u003cspan class=\"syntax-literal\"u003eNoneu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e i == u003cspan class=\"syntax-number\"u003e-1u003c/spanu003e u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e i u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e i u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e shape)\n\n tf_shape = tuple(g.get_tensor_by_name(name + u003cspan class=\"syntax-string\"u003e\":0\"u003c/spanu003e).shape.as_list())\n\n shapes.append({u003cspan class=\"syntax-string\"u003e\"Core ML shape\"u003c/spanu003e: coreml_shape, u003cspan class=\"syntax-string\"u003e\"TF shape\"u003c/spanu003e: tf_shape})\n names.append(name)\n ranks.append(len(coreml_shape))\n\n\n columns = [shapes[i] u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e i u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e np.argsort(ranks)[::u003cspan class=\"syntax-number\"u003e-1u003c/spanu003e]]\n indices = [names[i] u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e i u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e np.argsort(ranks)[::u003cspan class=\"syntax-number\"u003e-1u003c/spanu003e]]\n\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e pd.DataFrame(columns, index= indices)"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10153/3/710F0174-7EF1-4E55-9E84-7699484D2B1F/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10153/3/710F0174-7EF1-4E55-9E84-7699484D2B1F/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10153/3/710F0174-7EF1-4E55-9E84-7699484D2B1F/transcripts/wwdc2020-10153-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10153/3/710F0174-7EF1-4E55-9E84-7699484D2B1F/wwdc2020_10153_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10153/3/710F0174-7EF1-4E55-9E84-7699484D2B1F/wwdc2020_10153_sd.mp4",
"duration": 1876
},
"related": {
"activities": [
"wwdc2020-10152",
"wwdc2020-10638",
"wwdc2020-10711",
"wwdc2020-10717",
"wwdc2020-10718",
"wwdc2020-10719"
],
"resources": [
1029,
1028,
27
]
}
},
{
"id": "wwdc2020-10163",
"staticContentId": 3606,
"eventContentId": 10163,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10163",
"description": "Dive into the microscopic world of low-level bits and bytes that underlie every Objective-C and Swift class. Find out how recent changes to internal data structures, method lists, and tagged pointers provide better performance and lower memory usage. We’ll demonstrate how to recognize and fix crashes in code that depend on internal details, and show you how to keep your code unaffected by changes to the runtime.",
"title": "Advancements in the Objective-C runtime",
"originalPublishingDate": "2020-06-26T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"topicIds": [
32
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Use the heap command to calculate memory savings",
"startTimeSeconds": 337,
"endTimeSeconds": 400,
"language": "bash",
"code": "heap Mail | egrep u003cspan class=\"syntax-string\"u003e'class_rw|COUNT'u003c/spanu003e"
},
{
"title": "Use the APIs",
"startTimeSeconds": 455,
"endTimeSeconds": 477,
"language": "objectivec",
"code": "class_getName\n\nclass_getSuperclass\n\nclass_copyMethodList"
},
{
"title": "Use the APIs",
"startTimeSeconds": 878,
"endTimeSeconds": 890,
"language": "objectivec",
"code": "method_getName\n\nmethod_getTypeEncoding\n\nmethod_getImplementation"
},
{
"title": "Use the APIs",
"startTimeSeconds": 1312,
"endTimeSeconds": 1348,
"language": "objectivec",
"code": "u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e ([obj isKindOfClass:[u003cspan class=\"syntax-built_in\"u003eNSStringu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e]]) {\n u003cspan class=\"syntax-comment\"u003e// a stringu003c/spanu003e\n}\nu003cspan class=\"syntax-built_in\"u003eNSUIntegeru003c/spanu003e length = [obj length];\n\n\nu003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e (u003cspan class=\"syntax-built_in\"u003eCFGetTypeIDu003c/spanu003e(obj) == u003cspan class=\"syntax-built_in\"u003eCFStringGetTypeIDu003c/spanu003e()) {\n u003cspan class=\"syntax-comment\"u003e// a stringu003c/spanu003e\n}\nu003cspan class=\"syntax-built_in\"u003eCFIndexu003c/spanu003e length = u003cspan class=\"syntax-built_in\"u003eCFStringGetLengthu003c/spanu003e(obj);"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10163/5/69E6CEAB-D828-495C-B745-D48BF721F796/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10163/5/69E6CEAB-D828-495C-B745-D48BF721F796/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10163/5/69E6CEAB-D828-495C-B745-D48BF721F796/transcripts/wwdc2020-10163-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10163/5/69E6CEAB-D828-495C-B745-D48BF721F796/wwdc2020_10163_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10163/5/69E6CEAB-D828-495C-B745-D48BF721F796/wwdc2020_10163_sd.mp4",
"duration": 1385
},
"related": {
"activities": [
"wwdc2020-10648"
],
"resources": [
1201,
1200,
848
]
}
},
{
"id": "wwdc2020-10074",
"staticContentId": 3511,
"eventContentId": 10074,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10074",
"description": "“Sorry, there was a problem with the app...\"\r\n\r\nDon’t let Siri errors get you down: Learn how to debug your Siri intents and create great integrations people can use through voice or the Shortcuts app. We’ll look at common intent errors, how to test for them, and the path to a seamless Siri experience for your app.",
"title": "Decipher and deal with common Siri errors",
"originalPublishingDate": "2020-06-26T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"tvOS",
"watchOS"
],
"keywords": [
"extensions",
"in-app intent handling",
"intents",
"intentsui",
"shortcuts",
"siri",
"sirikit"
],
"topicIds": [
35,
33,
21,
13
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10074/3/8D3993B6-C13D-4BD2-A35A-D5F6D820C45B/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10074/3/8D3993B6-C13D-4BD2-A35A-D5F6D820C45B/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10074/3/8D3993B6-C13D-4BD2-A35A-D5F6D820C45B/transcripts/wwdc2020-10074-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10074/3/8D3993B6-C13D-4BD2-A35A-D5F6D820C45B/wwdc2020_10074_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10074/3/8D3993B6-C13D-4BD2-A35A-D5F6D820C45B/wwdc2020_10074_sd.mp4",
"duration": 129
},
"related": {
"activities": [
"wwdc2020-10053",
"wwdc2020-10060",
"wwdc2020-10061",
"wwdc2020-10068",
"wwdc2020-10071",
"wwdc2020-10073",
"wwdc2020-10083",
"wwdc2020-10084",
"wwdc2020-10086",
"wwdc2020-10088",
"wwdc2020-10190",
"wwdc2020-10200",
"wwdc2020-10203",
"wwdc2020-10839",
"wwdc2020-10877",
"wwdc2020-10878",
"wwdc2020-10914",
"wwdc2020-10917",
"wwdc2020-10963"
],
"resources": [
1109,
1108,
350
]
}
},
{
"id": "wwdc2020-10746",
"staticContentId": 3615,
"eventContentId": 10746,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=vi65u9ai",
"description": "",
"title": "The suite life of testing",
"articleID": "FB6808A0-A12B-44CC-BA5B-29E2B82A6885",
"articlePermalinkKey": "vi65u9ai",
"originalPublishingDate": "2020-06-22T01:00:55-07:00",
"publishingExpiryDate": "2025-06-22T00:52:10-07:00",
"topicIds": [
],
"type": "Article",
"images": [
"square",
"wide"
],
"related": {
"activities": [
"wwdc2020-10091",
"wwdc2020-10638"
]
}
},
{
"id": "wwdc2020-10083",
"staticContentId": 3512,
"eventContentId": 10083,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10083",
"description": "Discover how you can help people get ready for a good night's sleep by surfacing your app's actions for Wind Down Shortcuts, part of the new Sleep experience. Learn more about how Wind Down works. Find out how you can build intents that expose features in your app like guided meditations, soothing audio stories, or many other categories. And explore how you can surface those features on someone's device before bedtime.",
"title": "Integrate your app with Wind Down",
"originalPublishingDate": "2020-06-26T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"watchOS"
],
"keywords": [
"intents",
"intentsui",
"shortcuts",
"siri",
"sirikit",
"sleep",
"wind down"
],
"topicIds": [
21,
14,
13
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10083/3/0A7396FB-7C58-496C-BB03-C3FC6F95A070/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10083/3/0A7396FB-7C58-496C-BB03-C3FC6F95A070/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10083/3/0A7396FB-7C58-496C-BB03-C3FC6F95A070/transcripts/wwdc2020-10083-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10083/3/0A7396FB-7C58-496C-BB03-C3FC6F95A070/wwdc2020_10083_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10083/3/0A7396FB-7C58-496C-BB03-C3FC6F95A070/wwdc2020_10083_sd.mp4",
"duration": 659
},
"related": {
"activities": [
"wwdc2020-10053",
"wwdc2020-10060",
"wwdc2020-10061",
"wwdc2020-10068",
"wwdc2020-10069",
"wwdc2020-10071",
"wwdc2020-10073",
"wwdc2020-10074",
"wwdc2020-10084",
"wwdc2020-10086",
"wwdc2020-10088",
"wwdc2020-10190",
"wwdc2020-10200",
"wwdc2020-10203",
"wwdc2020-10839",
"wwdc2020-10877",
"wwdc2020-10878",
"wwdc2020-10914",
"wwdc2020-10917",
"wwdc2020-10963"
],
"resources": [
1111,
1110,
866
]
}
},
{
"id": "wwdc2020-10680",
"staticContentId": 3498,
"eventContentId": 10680,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10680",
"description": "Fine-tune your Objective-C headers to work beautifully in Swift. We’ll show you how to take an unwieldy Objective-C framework and transform it into an API that feels right at home. Learn about the suite of annotations you can use to provide richer type information, more idiomatic names, and better errors to Swift. And discover Objective-C conventions you might not have known about that are key to a well-behaved Swift API.\r\n\r\nTo get the most out of this session, you should be familiar with Swift and Objective-C.\r\n\r\nFor more on working with Swift and Objective-C, check out our Developer Documentation and take a look at “Behind the Scenes of the Xcode Build Process” from WWDC18.",
"title": "Refine Objective-C frameworks for Swift",
"originalPublishingDate": "2020-06-26T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"topicIds": [
36,
32
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Describe nullability to control optionals (method and property annotations)",
"startTimeSeconds": 283,
"endTimeSeconds": 413,
"language": "objectivec",
"code": "u003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// SKMission.hu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// View the generated interface to see how Swift imports this header.u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\n\nu003cspan class=\"syntax-meta\"u003e#import u003cspan class=\"syntax-meta-string\"u003eu0026lt;Foundation/Foundation.hu0026gt;u003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003e@interfaceu003c/spanu003e u003cspan class=\"syntax-title\"u003eSKMissionu003c/spanu003e : u003cspan class=\"syntax-title\"u003eNSObjectu003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003e@propertyu003c/spanu003e (u003cspan class=\"syntax-keyword\"u003ereadonlyu003c/spanu003e, u003cspan class=\"syntax-keyword\"u003enullableu003c/spanu003e) u003cspan class=\"syntax-built_in\"u003eNSStringu003c/spanu003e *name;\n\n- (u003cspan class=\"syntax-keyword\"u003enonnullu003c/spanu003e u003cspan class=\"syntax-keyword\"u003einstancetypeu003c/spanu003e)initWithName:(u003cspan class=\"syntax-keyword\"u003enullableu003c/spanu003e u003cspan class=\"syntax-built_in\"u003eNSStringu003c/spanu003e *)name;\n\nu003cspan class=\"syntax-keyword\"u003e@endu003c/spanu003e"
},
{
"title": "Describe nullability to control optionals (ASSUME_NONNULL blocks)",
"startTimeSeconds": 413,
"endTimeSeconds": 434,
"language": "objectivec",
"code": "u003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// SKMission.hu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// View the generated interface to see how Swift imports this header.u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\n\nu003cspan class=\"syntax-meta\"u003e#import u003cspan class=\"syntax-meta-string\"u003eu0026lt;Foundation/Foundation.hu0026gt;u003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-built_in\"u003eNS_ASSUME_NONNULL_BEGINu003c/spanu003e\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003e@interfaceu003c/spanu003e u003cspan class=\"syntax-title\"u003eSKMissionu003c/spanu003e : u003cspan class=\"syntax-title\"u003eNSObjectu003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003e@propertyu003c/spanu003e (u003cspan class=\"syntax-keyword\"u003ereadonlyu003c/spanu003e, u003cspan class=\"syntax-keyword\"u003enullableu003c/spanu003e) u003cspan class=\"syntax-built_in\"u003eNSStringu003c/spanu003e *name;\n\n- (u003cspan class=\"syntax-keyword\"u003einstancetypeu003c/spanu003e)initWithName:(u003cspan class=\"syntax-keyword\"u003enullableu003c/spanu003e u003cspan class=\"syntax-built_in\"u003eNSStringu003c/spanu003e *)name;\n\nu003cspan class=\"syntax-keyword\"u003e@endu003c/spanu003e\n\nu003cspan class=\"syntax-built_in\"u003eNS_ASSUME_NONNULL_ENDu003c/spanu003e"
},
{
"title": "Describe nullability to control optionals (qualifiers)",
"startTimeSeconds": 434,
"endTimeSeconds": 489,
"language": "objectivec",
"code": "u003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// Misc.hu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// View the generated interface to see how Swift imports this header.u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\n\nu003cspan class=\"syntax-meta\"u003e#import u003cspan class=\"syntax-meta-string\"u003eu0026lt;Foundation/Foundation.hu0026gt;u003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-built_in\"u003eNSStringu003c/spanu003e * _Nonnull u003cspan class=\"syntax-keyword\"u003econstu003c/spanu003e u003cspan class=\"syntax-built_in\"u003eSKRocketSaturnVu003c/spanu003e;\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003e@interfaceu003c/spanu003e u003cspan class=\"syntax-title\"u003eResourceValueContaineru003c/spanu003e : u003cspan class=\"syntax-title\"u003eNSObjectu003c/spanu003eu003c/spanu003e\n\n- (u003cspan class=\"syntax-built_in\"u003eBOOLu003c/spanu003e)getResourceValue:(u003cspan class=\"syntax-keyword\"u003eidu003c/spanu003e _Nullable * _Nonnull)outValue error:(u003cspan class=\"syntax-built_in\"u003eNSErroru003c/spanu003e**)error;\n\nu003cspan class=\"syntax-keyword\"u003e@endu003c/spanu003e"
},
{
"title": "Finding nullability mistakes with Objective-C tools",
"startTimeSeconds": 489,
"endTimeSeconds": 617,
"language": "objectivec",
"code": "u003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// SKMission.hu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\n\nu003cspan class=\"syntax-meta\"u003e#import u003cspan class=\"syntax-meta-string\"u003eu0026lt;Foundation/Foundation.hu0026gt;u003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003e@interfaceu003c/spanu003e u003cspan class=\"syntax-title\"u003eSKMissionu003c/spanu003e : u003cspan class=\"syntax-title\"u003eNSObjectu003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003e@propertyu003c/spanu003e (u003cspan class=\"syntax-keyword\"u003estrongu003c/spanu003e, u003cspan class=\"syntax-keyword\"u003enonnullu003c/spanu003e) u003cspan class=\"syntax-built_in\"u003eNSStringu003c/spanu003e *rocket;\nu003cspan class=\"syntax-keyword\"u003e@propertyu003c/spanu003e (u003cspan class=\"syntax-keyword\"u003estrongu003c/spanu003e, u003cspan class=\"syntax-keyword\"u003enonnullu003c/spanu003e) u003cspan class=\"syntax-built_in\"u003eNSStringu003c/spanu003e *capsule;\n\nu003cspan class=\"syntax-keyword\"u003e@endu003c/spanu003e\n\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// SKRocket.hu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\n\nu003cspan class=\"syntax-meta\"u003e#import u003cspan class=\"syntax-meta-string\"u003eu0026lt;Foundation/Foundation.hu0026gt;u003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eexternu003c/spanu003e u003cspan class=\"syntax-built_in\"u003eNSStringu003c/spanu003e *_Nonnull u003cspan class=\"syntax-keyword\"u003econstu003c/spanu003e u003cspan class=\"syntax-built_in\"u003eSKRocketSaturnVu003c/spanu003e;\n\nu003cspan class=\"syntax-comment\"u003e// u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// SKMission.mu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// Try building this file and then try analyzing it.u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\n\nu003cspan class=\"syntax-meta\"u003e#import u003cspan class=\"syntax-meta-string\"u003e\"SKRocket.h\"u003c/spanu003eu003c/spanu003e\nu003cspan class=\"syntax-meta\"u003e#import u003cspan class=\"syntax-meta-string\"u003e\"SKMission.h\"u003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003e@implementationu003c/spanu003e u003cspan class=\"syntax-title\"u003eSKMissionu003c/spanu003e @u003cspan class=\"syntax-title\"u003eendu003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003e@interfaceu003c/spanu003e u003cspan class=\"syntax-title\"u003eSKMissionConfiguratoru003c/spanu003e : u003cspan class=\"syntax-title\"u003eNSObjectu003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003e@propertyu003c/spanu003e (u003cspan class=\"syntax-keyword\"u003estrongu003c/spanu003e, u003cspan class=\"syntax-keyword\"u003enullableu003c/spanu003e) u003cspan class=\"syntax-built_in\"u003eSKMissionu003c/spanu003e *mission;\n\nu003cspan class=\"syntax-keyword\"u003e@endu003c/spanu003e\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003e@implementationu003c/spanu003e u003cspan class=\"syntax-title\"u003eSKMissionConfiguratoru003c/spanu003eu003c/spanu003e\n\n- (u003cspan class=\"syntax-keyword\"u003evoidu003c/spanu003e)testBadUseWithWarning {\n [u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.mission setCapsule:u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e];\n}\n\n- (u003cspan class=\"syntax-keyword\"u003evoidu003c/spanu003e)testBadUseWithStaticAnalyzer:(u003cspan class=\"syntax-built_in\"u003eBOOLu003c/spanu003e)missionIsSkylab1 {\n u003cspan class=\"syntax-built_in\"u003eNSStringu003c/spanu003e *capsule = u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e;\n\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e (!missionIsSkylab1) {\n capsule = u003cspan class=\"syntax-built_in\"u003eSKCapsuleApolloCSMu003c/spanu003e;\n }\n \n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.mission.capsule = capsule;\n}\n\nu003cspan class=\"syntax-keyword\"u003e@endu003c/spanu003e"
},
{
"title": "Use Objective-C generics for Foundation types",
"startTimeSeconds": 667,
"endTimeSeconds": 693,
"language": "objectivec",
"code": "u003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// SKAstronaut.hu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\n\nu003cspan class=\"syntax-meta\"u003e#import u003cspan class=\"syntax-meta-string\"u003eu0026lt;Foundation/Foundation.hu0026gt;u003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-built_in\"u003eNS_ASSUME_NONNULL_BEGINu003c/spanu003e\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003e@interfaceu003c/spanu003e u003cspan class=\"syntax-title\"u003eSKAstronautu003c/spanu003e : u003cspan class=\"syntax-title\"u003eNSObjectu003c/spanu003eu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// Stub declarationu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003e@endu003c/spanu003e\n\nu003cspan class=\"syntax-built_in\"u003eNS_ASSUME_NONNULL_ENDu003c/spanu003e\n\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// SKMission.hu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// View the generated interface to see how Swift imports this header.u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\n\nu003cspan class=\"syntax-meta\"u003e#import u003cspan class=\"syntax-meta-string\"u003eu0026lt;Foundation/Foundation.hu0026gt;u003c/spanu003eu003c/spanu003e\nu003cspan class=\"syntax-meta\"u003e#import u003cspan class=\"syntax-meta-string\"u003eu0026lt;SpaceKit/SKAstronaut.hu0026gt;u003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-built_in\"u003eNS_ASSUME_NONNULL_BEGINu003c/spanu003e\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003e@interfaceu003c/spanu003e u003cspan class=\"syntax-title\"u003eSKMissionu003c/spanu003e : u003cspan class=\"syntax-title\"u003eNSObjectu003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003e@propertyu003c/spanu003e (u003cspan class=\"syntax-keyword\"u003ereadonlyu003c/spanu003e) u003cspan class=\"syntax-built_in\"u003eNSArrayu003c/spanu003eu0026lt;u003cspan class=\"syntax-built_in\"u003eSKAstronautu003c/spanu003e *u0026gt; *crew;\n\nu003cspan class=\"syntax-keyword\"u003e@endu003c/spanu003e\n\nu003cspan class=\"syntax-built_in\"u003eNS_ASSUME_NONNULL_ENDu003c/spanu003e"
},
{
"title": "Use Int for numbers—unsigned types are for bitwise operations",
"startTimeSeconds": 693,
"endTimeSeconds": 803,
"language": "objectivec",
"code": "u003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// SKRocket.hu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// View the generated interface to see how Swift imports this header.u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\n\nu003cspan class=\"syntax-meta\"u003e#import u003cspan class=\"syntax-meta-string\"u003eu0026lt;Foundation/Foundation.hu0026gt;u003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-built_in\"u003eNS_ASSUME_NONNULL_BEGINu003c/spanu003e\n\nu003cspan class=\"syntax-built_in\"u003eNSIntegeru003c/spanu003e u003cspan class=\"syntax-built_in\"u003eSKRocketStageCountu003c/spanu003e(u003cspan class=\"syntax-built_in\"u003eNSStringu003c/spanu003e *);\n\nu003cspan class=\"syntax-built_in\"u003eNS_ASSUME_NONNULL_ENDu003c/spanu003e\n\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// NSData+xor.hu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// View the generated interface to see how Swift imports this header.u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\n\nu003cspan class=\"syntax-meta\"u003e#import u003cspan class=\"syntax-meta-string\"u003eu0026lt;Foundation/Foundation.hu0026gt;u003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003e@interfaceu003c/spanu003e u003cspan class=\"syntax-title\"u003eNSDatau003c/spanu003e (u003cspan class=\"syntax-title\"u003exoru003c/spanu003e)u003c/spanu003e\n\n- (u003cspan class=\"syntax-keyword\"u003evoidu003c/spanu003e)xorWithByte:(uint8_t)value;\n\nu003cspan class=\"syntax-keyword\"u003e@endu003c/spanu003e"
},
{
"title": "Strengthen stringly-typed constants",
"startTimeSeconds": 803,
"endTimeSeconds": 896,
"language": "objectivec",
"code": "u003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// SKRocket.hu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// View the generated interface to see how Swift imports this header.u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\n\nu003cspan class=\"syntax-meta\"u003e#import u003cspan class=\"syntax-meta-string\"u003eu0026lt;Foundation/Foundation.hu0026gt;u003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-built_in\"u003eNS_ASSUME_NONNULL_BEGINu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003etypedefu003c/spanu003e u003cspan class=\"syntax-built_in\"u003eNSStringu003c/spanu003e *u003cspan class=\"syntax-built_in\"u003eSKRocketu003c/spanu003e u003cspan class=\"syntax-built_in\"u003eNS_STRING_ENUMu003c/spanu003e;\n\nu003cspan class=\"syntax-keyword\"u003eexternu003c/spanu003e u003cspan class=\"syntax-built_in\"u003eSKRocketu003c/spanu003e u003cspan class=\"syntax-keyword\"u003econstu003c/spanu003e u003cspan class=\"syntax-built_in\"u003eSKRocketAtlasu003c/spanu003e;\nu003cspan class=\"syntax-keyword\"u003eexternu003c/spanu003e u003cspan class=\"syntax-built_in\"u003eSKRocketu003c/spanu003e u003cspan class=\"syntax-keyword\"u003econstu003c/spanu003e u003cspan class=\"syntax-built_in\"u003eSKRocketTitanIIu003c/spanu003e;\nu003cspan class=\"syntax-keyword\"u003eexternu003c/spanu003e u003cspan class=\"syntax-built_in\"u003eSKRocketu003c/spanu003e u003cspan class=\"syntax-keyword\"u003econstu003c/spanu003e u003cspan class=\"syntax-built_in\"u003eSKRocketSaturnIBu003c/spanu003e;\nu003cspan class=\"syntax-keyword\"u003eexternu003c/spanu003e u003cspan class=\"syntax-built_in\"u003eSKRocketu003c/spanu003e u003cspan class=\"syntax-keyword\"u003econstu003c/spanu003e u003cspan class=\"syntax-built_in\"u003eSKRocketSaturnVu003c/spanu003e;\n\nu003cspan class=\"syntax-built_in\"u003eNSIntegeru003c/spanu003e u003cspan class=\"syntax-built_in\"u003eSKRocketStageCountu003c/spanu003e(u003cspan class=\"syntax-built_in\"u003eSKRocketu003c/spanu003e);\n\nu003cspan class=\"syntax-built_in\"u003eNS_ASSUME_NONNULL_ENDu003c/spanu003e"
},
{
"title": "Specify initializer behavior",
"startTimeSeconds": 924,
"endTimeSeconds": 1200,
"language": "objectivec",
"code": "u003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// SKAstronaut.hu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// View the generated interface to see how Swift imports this header.u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\n\nu003cspan class=\"syntax-meta\"u003e#import u003cspan class=\"syntax-meta-string\"u003eu0026lt;Foundation/Foundation.hu0026gt;u003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-built_in\"u003eNS_ASSUME_NONNULL_BEGINu003c/spanu003e\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003e@interfaceu003c/spanu003e u003cspan class=\"syntax-title\"u003eSKAstronautu003c/spanu003e : u003cspan class=\"syntax-title\"u003eNSObjectu003c/spanu003eu003c/spanu003e\n\n- (u003cspan class=\"syntax-keyword\"u003einstancetypeu003c/spanu003e)initWithNameComponents:(u003cspan class=\"syntax-built_in\"u003eNSPersonNameComponentsu003c/spanu003e *)name u003cspan class=\"syntax-built_in\"u003eNS_DESIGNATED_INITIALIZERu003c/spanu003e;\n- (u003cspan class=\"syntax-keyword\"u003einstancetypeu003c/spanu003e)initWithName:(u003cspan class=\"syntax-built_in\"u003eNSStringu003c/spanu003e *)name;\n- (u003cspan class=\"syntax-keyword\"u003einstancetypeu003c/spanu003e)init u003cspan class=\"syntax-built_in\"u003eNS_UNAVAILABLEu003c/spanu003e;\n\nu003cspan class=\"syntax-keyword\"u003e@propertyu003c/spanu003e (u003cspan class=\"syntax-keyword\"u003estrongu003c/spanu003e, u003cspan class=\"syntax-keyword\"u003ereadwriteu003c/spanu003e) u003cspan class=\"syntax-built_in\"u003eNSPersonNameComponentsu003c/spanu003e *nameComponents;\nu003cspan class=\"syntax-keyword\"u003e@propertyu003c/spanu003e (u003cspan class=\"syntax-keyword\"u003ereadonlyu003c/spanu003e) u003cspan class=\"syntax-built_in\"u003eNSStringu003c/spanu003e *name;\n\nu003cspan class=\"syntax-keyword\"u003e@endu003c/spanu003e\n\nu003cspan class=\"syntax-built_in\"u003eNS_ASSUME_NONNULL_ENDu003c/spanu003e\n\nu003cspan class=\"syntax-comment\"u003e// u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// SKAstronaut.mu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// u003c/spanu003e\n\nu003cspan class=\"syntax-meta\"u003e#import u003cspan class=\"syntax-meta-string\"u003e\"SKAstronaut.h\"u003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003e@interfaceu003c/spanu003e u003cspan class=\"syntax-title\"u003eSKAstronautu003c/spanu003e ()u003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003e@propertyu003c/spanu003e (u003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e, u003cspan class=\"syntax-keyword\"u003ereadonlyu003c/spanu003e, u003cspan class=\"syntax-keyword\"u003estrongu003c/spanu003e) u003cspan class=\"syntax-built_in\"u003eNSPersonNameComponentsFormatteru003c/spanu003e *nameFormatter;\nu003cspan class=\"syntax-keyword\"u003e@endu003c/spanu003e\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003e@implementationu003c/spanu003e u003cspan class=\"syntax-title\"u003eSKAstronautu003c/spanu003eu003c/spanu003e\n\n- (u003cspan class=\"syntax-keyword\"u003eidu003c/spanu003e)initWithNameComponents:(u003cspan class=\"syntax-built_in\"u003eNSPersonNameComponentsu003c/spanu003e *)name {\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e = [u003cspan class=\"syntax-keyword\"u003esuperu003c/spanu003e init];\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e (u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e) {\n _name = name;\n }\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e;\n}\n\n- (u003cspan class=\"syntax-keyword\"u003eidu003c/spanu003e)initWithName:(u003cspan class=\"syntax-built_in\"u003eNSStringu003c/spanu003e *)name {\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e [u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e initWithNameComponents:[u003cspan class=\"syntax-built_in\"u003eSKAstronautu003c/spanu003e _componentsFromName:name]];\n}\n\n- (u003cspan class=\"syntax-keyword\"u003eidu003c/spanu003e)init {\n [u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e doesNotRecognizeSelector:_cmd];\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e;\n}\n\n- (u003cspan class=\"syntax-built_in\"u003eNSStringu003c/spanu003e *)name {\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e [u003cspan class=\"syntax-built_in\"u003eSKAstronautu003c/spanu003e.nameFormatter stringFromPersonNameComponents:u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.nameComponents];\n}\n\n+ (u003cspan class=\"syntax-built_in\"u003eNSPersonNameComponentsu003c/spanu003e*)_componentsFromName:(u003cspan class=\"syntax-built_in\"u003eNSStringu003c/spanu003e*)name {\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e [u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.nameFormatter personNameComponentsFromString:name];\n}\n\n+ (u003cspan class=\"syntax-built_in\"u003eNSPersonNameComponentsFormatteru003c/spanu003e *)nameFormatter {\n u003cspan class=\"syntax-keyword\"u003estaticu003c/spanu003e u003cspan class=\"syntax-built_in\"u003eNSPersonNameComponentsFormatteru003c/spanu003e *singleton;\n u003cspan class=\"syntax-keyword\"u003estaticu003c/spanu003e u003cspan class=\"syntax-built_in\"u003edispatch_once_tu003c/spanu003e onceToken;\n u003cspan class=\"syntax-built_in\"u003edispatch_onceu003c/spanu003e(u0026amp;onceToken, ^{\n singleton = [u003cspan class=\"syntax-built_in\"u003eNSPersonNameComponentsFormatteru003c/spanu003e new];\n });\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e singleton;\n}\n\nu003cspan class=\"syntax-keyword\"u003e@endu003c/spanu003e"
},
{
"title": "Follow the error handling convention",
"startTimeSeconds": 1200,
"endTimeSeconds": 1360,
"language": "objectivec",
"code": "u003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// SKMission.hu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// View the generated interface to see how Swift imports this header.u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\n\nu003cspan class=\"syntax-meta\"u003e#import u003cspan class=\"syntax-meta-string\"u003eu0026lt;Foundation/Foundation.hu0026gt;u003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-built_in\"u003eNS_ASSUME_NONNULL_BEGINu003c/spanu003e\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003e@interfaceu003c/spanu003e u003cspan class=\"syntax-title\"u003eSKMissionu003c/spanu003e : u003cspan class=\"syntax-title\"u003eNSObjectu003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-comment\"u003e/// \\returns \\c YES if saved; \\c NO with non-nil \\c *error if failed to save;u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e/// \\c NO with nil \\c *error` if nothing needed to be saved.u003c/spanu003e\n- (u003cspan class=\"syntax-built_in\"u003eBOOLu003c/spanu003e)saveToURL:(u003cspan class=\"syntax-built_in\"u003eNSURLu003c/spanu003e *)url error:(u003cspan class=\"syntax-built_in\"u003eNSErroru003c/spanu003e **)error u003cspan class=\"syntax-built_in\"u003eNS_SWIFT_NOTHROWu003c/spanu003e DEPRECATED_ATTRIBUTE;\n\nu003cspan class=\"syntax-comment\"u003e/// @param[out] wasDirty If provided, set to \\c YES if the file needed to beu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e/// saved or \\c NO if there weren’t any changes to save.u003c/spanu003e\n- (u003cspan class=\"syntax-built_in\"u003eBOOLu003c/spanu003e)saveToURL:(u003cspan class=\"syntax-built_in\"u003eNSURLu003c/spanu003e *)url wasDirty:(u003cspan class=\"syntax-keyword\"u003enullableu003c/spanu003e u003cspan class=\"syntax-built_in\"u003eBOOLu003c/spanu003e *)wasDirty error:(u003cspan class=\"syntax-built_in\"u003eNSErroru003c/spanu003e **)error;\n\nu003cspan class=\"syntax-keyword\"u003e@endu003c/spanu003e\n\nu003cspan class=\"syntax-built_in\"u003eNS_ASSUME_NONNULL_ENDu003c/spanu003e"
},
{
"title": "Refine an Objective-C API for Swift users",
"startTimeSeconds": 1360,
"endTimeSeconds": 1710,
"language": "objectivec",
"code": "u003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// SKMission.hu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// View the generated interface to see how Swift imports this header.u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\n\nu003cspan class=\"syntax-meta\"u003e#import u003cspan class=\"syntax-meta-string\"u003eu0026lt;Foundation/Foundation.hu0026gt;u003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-built_in\"u003eNS_ASSUME_NONNULL_BEGINu003c/spanu003e\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003e@interfaceu003c/spanu003e u003cspan class=\"syntax-title\"u003eSKMissionu003c/spanu003e : u003cspan class=\"syntax-title\"u003eNSObjectu003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-comment\"u003e/// \\returns \\c YES if saved; \\c NO with non-nil \\c *error if failed to save;u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e/// \\c NO with nil \\c *error` if nothing needed to be saved.u003c/spanu003e\n- (u003cspan class=\"syntax-built_in\"u003eBOOLu003c/spanu003e)saveToURL:(u003cspan class=\"syntax-built_in\"u003eNSURLu003c/spanu003e *)url error:(u003cspan class=\"syntax-built_in\"u003eNSErroru003c/spanu003e **)error u003cspan class=\"syntax-built_in\"u003eNS_SWIFT_NOTHROWu003c/spanu003e DEPRECATED_ATTRIBUTE;\n\nu003cspan class=\"syntax-comment\"u003e/// @param[out] wasDirty If provided, set to \\c YES if the file needed to beu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e/// saved or \\c NO if there weren’t any changes to save.u003c/spanu003e\n- (u003cspan class=\"syntax-built_in\"u003eBOOLu003c/spanu003e)saveToURL:(u003cspan class=\"syntax-built_in\"u003eNSURLu003c/spanu003e *)url wasDirty:(u003cspan class=\"syntax-keyword\"u003enullableu003c/spanu003e u003cspan class=\"syntax-built_in\"u003eBOOLu003c/spanu003e *)wasDirty error:(u003cspan class=\"syntax-built_in\"u003eNSErroru003c/spanu003e **)error u003cspan class=\"syntax-built_in\"u003eNS_REFINED_FOR_SWIFTu003c/spanu003e;\n\nu003cspan class=\"syntax-keyword\"u003e@endu003c/spanu003e\n\nu003cspan class=\"syntax-built_in\"u003eNS_ASSUME_NONNULL_ENDu003c/spanu003e\n\nu003cspan class=\"syntax-comment\"u003e// u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// SwiftExtensions.swiftu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\n\nimport Foundation\n\nextension u003cspan class=\"syntax-built_in\"u003eSKMissionu003c/spanu003e {\n public func save(to url: URL) throws -u0026gt; Bool {\n var wasDirty: ObjCBool = u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e\n try u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.__save(to: url, wasDirty: u0026amp;wasDirty)\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e wasDirty.boolValue\n }\n}"
},
{
"title": "Fix method names with NS_SWIFT_NAME",
"startTimeSeconds": 1895,
"endTimeSeconds": 1991,
"language": "objectivec",
"code": "u003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// SKMission.hu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// View the generated interface to see how Swift imports this header.u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\n\nu003cspan class=\"syntax-meta\"u003e#import u003cspan class=\"syntax-meta-string\"u003eu0026lt;Foundation/Foundation.hu0026gt;u003c/spanu003eu003c/spanu003e\nu003cspan class=\"syntax-meta\"u003e#import u003cspan class=\"syntax-meta-string\"u003eu0026lt;SKAstronaut/SKAstronaut.hu0026gt;u003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-built_in\"u003eNS_ASSUME_NONNULL_BEGINu003c/spanu003e\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003e@interfaceu003c/spanu003e u003cspan class=\"syntax-title\"u003eSKMissionu003c/spanu003e : u003cspan class=\"syntax-title\"u003eNSObjectu003c/spanu003eu003c/spanu003e\n\n- (u003cspan class=\"syntax-built_in\"u003eNSSetu003c/spanu003eu0026lt;u003cspan class=\"syntax-built_in\"u003eSKMissionu003c/spanu003e *u0026gt; *)previousMissionsFlownByAstronaut:(u003cspan class=\"syntax-built_in\"u003eSKAstronautu003c/spanu003e *)astronaut u003cspan class=\"syntax-built_in\"u003eNS_SWIFT_NAMEu003c/spanu003e(previousMissions(flownBy:));\n\nu003cspan class=\"syntax-keyword\"u003e@endu003c/spanu003e"
},
{
"title": "Rename and rework value types with NS_SWIFT_NAME",
"startTimeSeconds": 1992,
"endTimeSeconds": 2159,
"language": "objectivec",
"code": "u003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// SKFuelKind.hu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// View the generated interface to see how Swift imports this header.u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\n\nu003cspan class=\"syntax-meta\"u003e#import u003cspan class=\"syntax-meta-string\"u003eu0026lt;Foundation/Foundation.hu0026gt;u003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-built_in\"u003eNS_ASSUME_NONNULL_BEGINu003c/spanu003e\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003e@interfaceu003c/spanu003e u003cspan class=\"syntax-title\"u003eSKFuelu003c/spanu003e : u003cspan class=\"syntax-title\"u003eNSObjectu003c/spanu003eu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// Stub classu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003e@endu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003etypedefu003c/spanu003e u003cspan class=\"syntax-built_in\"u003eNS_ENUMu003c/spanu003e(u003cspan class=\"syntax-built_in\"u003eNSIntegeru003c/spanu003e, u003cspan class=\"syntax-built_in\"u003eSKFuelKindu003c/spanu003e) {\n u003cspan class=\"syntax-built_in\"u003eSKFuelKindH2u003c/spanu003e = u003cspan class=\"syntax-number\"u003e0u003c/spanu003e,\n u003cspan class=\"syntax-built_in\"u003eSKFuelKindCH4u003c/spanu003e = u003cspan class=\"syntax-number\"u003e1u003c/spanu003e,\n u003cspan class=\"syntax-built_in\"u003eSKFuelKindC12H26u003c/spanu003e = u003cspan class=\"syntax-number\"u003e2u003c/spanu003e\n} u003cspan class=\"syntax-built_in\"u003eNS_SWIFT_NAMEu003c/spanu003e(u003cspan class=\"syntax-built_in\"u003eSKFuelu003c/spanu003e.Kind);\n\nu003cspan class=\"syntax-built_in\"u003eNSStringu003c/spanu003e *u003cspan class=\"syntax-built_in\"u003eSKFuelKindToNSStringu003c/spanu003e(u003cspan class=\"syntax-built_in\"u003eSKFuelKindu003c/spanu003e kind)\n u003cspan class=\"syntax-built_in\"u003eNS_SWIFT_NAMEu003c/spanu003e(u003cspan class=\"syntax-keyword\"u003egetteru003c/spanu003e:u003cspan class=\"syntax-built_in\"u003eSKFuelKindu003c/spanu003e.description(u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e:));"
},
{
"title": "Add conformances to Objective-C types using custom Swift code",
"startTimeSeconds": 2159,
"endTimeSeconds": 2182,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eextensionu003c/spanu003e u003cspan class=\"syntax-title\"u003eSKFuelu003c/spanu003e.u003cspan class=\"syntax-title\"u003eKindu003c/spanu003e: u003cspan class=\"syntax-title\"u003eCustomStringConvertibleu003c/spanu003e u003c/spanu003e{}"
},
{
"title": "Improve error code enums",
"startTimeSeconds": 2222,
"endTimeSeconds": 2442,
"language": "objectivec",
"code": "u003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// SKError.hu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// SpaceKitu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e//u003c/spanu003e\n\nu003cspan class=\"syntax-meta\"u003e#import u003cspan class=\"syntax-meta-string\"u003eu0026lt;Foundation/Foundation.hu0026gt;u003c/spanu003eu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eexternu003c/spanu003e u003cspan class=\"syntax-built_in\"u003eNSStringu003c/spanu003e *u003cspan class=\"syntax-keyword\"u003econstu003c/spanu003e u003cspan class=\"syntax-built_in\"u003eSKErrorDomainu003c/spanu003e;\n\nu003cspan class=\"syntax-keyword\"u003etypedefu003c/spanu003e u003cspan class=\"syntax-built_in\"u003eNS_ERROR_ENUMu003c/spanu003e(u003cspan class=\"syntax-built_in\"u003eSKErrorDomainu003c/spanu003e, u003cspan class=\"syntax-built_in\"u003eSKErrorCodeu003c/spanu003e) {\n u003cspan class=\"syntax-built_in\"u003eSKErrorLaunchAbortedu003c/spanu003e = u003cspan class=\"syntax-number\"u003e1u003c/spanu003e,\n u003cspan class=\"syntax-built_in\"u003eSKErrorLaunchOutOfRangeu003c/spanu003e,\n u003cspan class=\"syntax-built_in\"u003eSKErrorRapidUnscheduledDisassemblyu003c/spanu003e,\n u003cspan class=\"syntax-built_in\"u003eSKErrorNotGoingToSpaceTodayu003c/spanu003e\n};"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10680/6/733DC040-9073-4427-B411-BBF7BEE212B4/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10680/6/733DC040-9073-4427-B411-BBF7BEE212B4/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10680/6/733DC040-9073-4427-B411-BBF7BEE212B4/transcripts/wwdc2020-10680-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10680/6/733DC040-9073-4427-B411-BBF7BEE212B4/wwdc2020_10680_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10680/6/733DC040-9073-4427-B411-BBF7BEE212B4/wwdc2020_10680_sd.mp4",
"duration": 2562
},
"related": {
"activities": [
"wwdc2018-415"
],
"resources": [
1091,
1090,
761
]
}
},
{
"id": "wwdc2020-10666",
"staticContentId": 3473,
"eventContentId": 10666,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10666",
"description": "When you adopt the Account Authentication Modification Extension, you can provide people with fast, easy account security upgrades to use Sign in with Apple and strong passwords in the iCloud Keychain Password Manager. We’ll show you how to add these upgrade flows to your app with the Account Authentication Modification Extension, the AuthenticationServices Framework API, and best practices required for a smooth password transition.",
"title": "One-tap account security upgrades",
"originalPublishingDate": "2020-06-23T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS"
],
"keywords": [
"2fa",
"account security",
"app clip",
"asextensionlocalizedfailurereasonerrorkey",
"aspasswordcredential",
"authorizeupgrade",
"autofill",
"breached",
"breaches",
"changepasswordwithoutuserinteraction",
"completechangepasswordrequest",
"factor",
"in-app",
"login",
"prepareinterfacetochangepassword",
"prepareinterfacetoconvertaccounttosigninwithapple",
"second",
"security code",
"sign in",
"sms",
".well-known"
],
"topicIds": [
19,
22,
20
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10666/6/D7AC2207-1C98-4C40-B53E-B41D8B673E40/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10666/6/D7AC2207-1C98-4C40-B53E-B41D8B673E40/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10666/5/D4B7397B-A103-47AB-B97A-5DFFDCC3DB05/transcripts/wwdc2020-10666-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10666/6/D7AC2207-1C98-4C40-B53E-B41D8B673E40/wwdc2020_10666_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10666/6/D7AC2207-1C98-4C40-B53E-B41D8B673E40/wwdc2020_10666_sd.mp4",
"duration": 1446
},
"related": {
"activities": [
"wwdc2020-10120",
"wwdc2020-10173",
"wwdc2020-10740",
"wwdc2020-10743",
"wwdc2020-10744",
"wwdc2020-10836",
"wwdc2019-706",
"wwdc2017-206"
],
"resources": [
1075,
1074,
578,
527,
432,
426
]
}
},
{
"id": "wwdc2020-10639",
"staticContentId": 3447,
"eventContentId": 10639,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10639",
"description": "We've made significant strides in bringing crucial device management features to macOS. Discover how these features can help you manage your all your devices using the same tools and technologies. Get details on changes coming this year and how they will impact your deployment workflows, as well as some new management capabilities you can use to secure iOS and iPadOS devices in your organization.",
"title": "What's new in managing Apple devices",
"originalPublishingDate": "2020-06-23T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS"
],
"keywords": [
"configuration",
"configurator",
"distribution",
"enterprise",
"management",
"mdm",
"privacy",
"security"
],
"topicIds": [
44
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10639/6/CA966211-6AC2-4D0B-B067-5B260747CD5F/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10639/6/CA966211-6AC2-4D0B-B067-5B260747CD5F/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10639/5/057764DA-08A0-45F7-8FFE-F256D8F63FA8/transcripts/wwdc2020-10639-transcripts.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10639/6/CA966211-6AC2-4D0B-B067-5B260747CD5F/wwdc2020_10639_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10639/6/CA966211-6AC2-4D0B-B067-5B260747CD5F/wwdc2020_10639_sd.mp4",
"duration": 1418
},
"related": {
"activities": [
"wwdc2020-10138",
"wwdc2020-10139",
"wwdc2020-10223",
"wwdc2020-10638",
"wwdc2020-10754",
"wwdc2020-10844"
],
"resources": [
1045,
1044,
586,
581,
136
]
}
},
{
"id": "wwdc2020-10616",
"staticContentId": 3728,
"eventContentId": 10616,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10616",
"description": "Track down even the trickiest GPU-side programming errors with enhanced reporting in Xcode 12. While Metal’s API validation layer can catch most problems in a project, GPU errors can cause a host of difficult-to-debug issues.\r\n\r\nGet an introduction to GPU-side errors and learn how to find and eliminate problems like visual corruption, infinite loop timeouts, out of bounds memory accesses, nil resource access, or invalid resource residency with Xcode 12. Discover how to enable enhanced command buffer error reporting and shader validation, use them effectively as part of your debugging strategy, and automate them in your production pipeline.",
"title": "Debug GPU-side errors in Metal",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS"
],
"topicIds": [
33,
26,
25,
27
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Enable enhanced command buffer errors",
"startTimeSeconds": 220,
"endTimeSeconds": 234,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e desc = u003cspan class=\"syntax-type\"u003eMTLCommandBufferDescriptoru003c/spanu003e()\ndesc.errorOptions = .encoderExecutionStatus\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e commandBuffer = commandQueue.makeCommandBuffer(descriptor: desc)"
},
{
"title": "Processing enhanced command buffer errors",
"startTimeSeconds": 235,
"endTimeSeconds": 270,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e error = commandBuffer.error u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e u003cspan class=\"syntax-type\"u003eNSError?u003c/spanu003e {\n\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e encoderInfos =\n error.userInfo[u003cspan class=\"syntax-type\"u003eMTLCommandBufferEncoderInfoErrorKeyu003c/spanu003e]\n u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e? [u003cspan class=\"syntax-type\"u003eMTLCommandBufferEncoderInfou003c/spanu003e] {\n\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e info u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e encoderInfos {\n u003cspan class=\"syntax-built_in\"u003eprintu003c/spanu003e(info.label + info.debugSignposts.joined())\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e info.errorState == .faulted {\n u003cspan class=\"syntax-built_in\"u003eprintu003c/spanu003e(info.label + u003cspan class=\"syntax-string\"u003e\" faulted!\"u003c/spanu003e)\n }\n }\n }\n}"
},
{
"title": "Command buffer logs API",
"startTimeSeconds": 939,
"endTimeSeconds": 998,
"language": "swift",
"code": "commandBuffer.addCompletedHandler { (commandBuffer) u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e log u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e commandBuffer.logs {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e encoderLabel = log.encoderLabel ?? u003cspan class=\"syntax-string\"u003e\"Unknown Label\"u003c/spanu003e\n u003cspan class=\"syntax-built_in\"u003eprintu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Faulting encoder \\\"\\(encoderLabel)\\\"\"u003c/spanu003e)\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e debugLocation = log.debugLocation,\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e functionName = debugLocation.functionName\n u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e\n }\n u003cspan class=\"syntax-built_in\"u003eprintu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Faulting function \\(functionName):\\(debugLocation.line):\\(debugLocation.column)\"u003c/spanu003e)\n }\n}"
},
{
"title": "Accessing the log",
"startTimeSeconds": 940,
"endTimeSeconds": 941,
"language": "bash",
"code": "u003cspan class=\"syntax-built_in\"u003elogu003c/spanu003e stream --predicate u003cspan class=\"syntax-string\"u003e\"subsystem = 'com.apple.Metal' and category = 'GPUDebug'\"u003c/spanu003e"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10616/5/F585B9C6-DBD8-4C59-B210-5228EF5B86B1/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10616/5/F585B9C6-DBD8-4C59-B210-5228EF5B86B1/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10616/4/F1AB0F2F-D3BF-4F96-8581-67C84D7009EB/transcripts/wwdc2020-10616-transcripts.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10616/5/F585B9C6-DBD8-4C59-B210-5228EF5B86B1/wwdc2020_10616_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10616/5/F585B9C6-DBD8-4C59-B210-5228EF5B86B1/wwdc2020_10616_sd.mp4",
"duration": 1256
},
"related": {
"activities": [
"wwdc2020-10602",
"wwdc2020-10605",
"wwdc2020-10615",
"wwdc2020-10631",
"wwdc2020-10632",
"wwdc2020-10810",
"wwdc2020-10811",
"wwdc2020-10812",
"wwdc2020-10813",
"wwdc2020-10814",
"wwdc2020-10815",
"wwdc2020-10816",
"wwdc2020-10817"
],
"resources": [
1277,
1276,
38
]
}
},
{
"id": "wwdc2020-10738",
"staticContentId": 3397,
"eventContentId": 10738,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=wbjyi33z",
"description": "",
"title": "Locating people, places, and things",
"articleID": "AC6B4752-D7F6-417C-862B-14B4BEAF625A",
"articlePermalinkKey": "wbjyi33z",
"originalPublishingDate": "2020-06-22T00:00:49-07:00",
"publishingExpiryDate": "2025-06-22T01:56:59-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS"
],
"topicIds": [
17
],
"type": "Article",
"images": [
"square",
"wide"
],
"related": {
"activities": [
"wwdc2020-10638"
]
}
},
{
"id": "wwdc2020-10142",
"staticContentId": 3822,
"eventContentId": 10142,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10142",
"description": "Learn how to build focused enterprise apps that work well together. In this session, we’ll introduce you to Apple Retail’s suite of enterprise apps, which help employees interact with customers, track operations, manage stores, and stay connected. Discover how Apple Retail created a unified set of apps by adopting Swift Packages and testing for app scalability. And explore how managing apps in production with configurations can help tailor app suites to different regions and locations.",
"title": "Build scalable enterprise app suites",
"originalPublishingDate": "2020-06-26T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS"
],
"keywords": [
"enterprise",
"swift packages",
"testing"
],
"topicIds": [
70
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "App Groups",
"startTimeSeconds": 122,
"endTimeSeconds": 142,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e sharedDefaults = u003cspan class=\"syntax-type\"u003eUserDefaultsu003c/spanu003e(suiteName: “group.com.apple.myappgroupu003cspan class=\"syntax-string\"u003e\")!\n \nsharedDefaults.set(\"u003c/spanu003eu003cspan class=\"syntax-type\"u003eMyu003c/spanu003e u003cspan class=\"syntax-type\"u003eCoolu003c/spanu003e u003cspan class=\"syntax-type\"u003eValueu003c/spanu003eu003cspan class=\"syntax-string\"u003e\", forKey: \"u003c/spanu003eu003cspan class=\"syntax-type\"u003eMyKeyNameu003c/spanu003eu003cspan class=\"syntax-string\"u003e\")\n \nlet myKeyNameValue = sharedDefaults.string(forKey: \"u003c/spanu003eu003cspan class=\"syntax-type\"u003eMyKeyNameu003c/spanu003eu003cspan class=\"syntax-string\"u003e\")u003c/spanu003e"
},
{
"title": "BarcodeScannerViewController",
"startTimeSeconds": 304,
"endTimeSeconds": 321,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e RetailScanner\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e scanOptions = u003cspan class=\"syntax-type\"u003eBarcodeScanOptionsu003c/spanu003e()\nscanOptions.scanRegion = .regular\nscanOptions.shouldAddSupplementaryView = u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e\nscanOptions.shouldShowBarcodeDetector = u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e barcodeViewController = u003cspan class=\"syntax-type\"u003eBarcodeScannerViewControlleru003c/spanu003e(scanOptions: scanOptions)\nbarcodeViewController.delegate = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e"
},
{
"title": "OCRScannerViewController",
"startTimeSeconds": 329,
"endTimeSeconds": 349,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e RetailScanner\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e scanOptions = u003cspan class=\"syntax-type\"u003eOCRScanOptionsu003c/spanu003e(\n scanRegion: .custom(u003cspan class=\"syntax-type\"u003eCGSizeu003c/spanu003e(width: u003cspan class=\"syntax-number\"u003e400u003c/spanu003e, height: u003cspan class=\"syntax-number\"u003e100u003c/spanu003e)),\n accessibilityBehavior: .vibrate,\n shouldAddSupplementaryView: u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e,\n validation: u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e, \n shouldShowResultView: u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e\n)\nscanOptions.recognitionLevel = .fast\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e ocrViewController = u003cspan class=\"syntax-type\"u003eOCRScannerViewControlleru003c/spanu003e(\n scanOptions: scanOptions\n)\nocrViewController.delegate = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e"
},
{
"title": "Config-driven UI - Client based configuration hosted by server",
"startTimeSeconds": 746,
"endTimeSeconds": 760,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003econfiguredCellForLabelu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e customerInfoField: CustomerInfoField, at indexPath: IndexPath)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eUITableViewCellu003c/spanu003e { . . . }\n\n\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003econfiguredCellForPhoneNumberu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e customerInfoField: CustomerInfoField, at indexPath: IndexPath)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eUITableViewCellu003c/spanu003e { . . . }"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10142/6/570BD5D0-7BC7-4D3A-A1EC-E67D13CD87E0/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10142/6/570BD5D0-7BC7-4D3A-A1EC-E67D13CD87E0/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10142/6/570BD5D0-7BC7-4D3A-A1EC-E67D13CD87E0/transcripts/wwdc2020-10142-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10142/6/570BD5D0-7BC7-4D3A-A1EC-E67D13CD87E0/wwdc2020_10142_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10142/6/570BD5D0-7BC7-4D3A-A1EC-E67D13CD87E0/wwdc2020_10142_sd.mp4",
"duration": 916
},
"related": {
"activities": [
"wwdc2020-10091",
"wwdc2020-10169",
"wwdc2020-10638",
"wwdc2019-410",
"wwdc2019-413",
"wwdc2019-417",
"wwdc2018-407",
"wwdc2018-417",
"wwdc2015-406"
],
"resources": [
1315,
1314
]
}
},
{
"id": "wwdc2020-10004",
"staticContentId": 3349,
"eventContentId": 10004,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10004",
"description": "Make routine tasks in App Store Connect a thing of the past when you automate your workflow with the App Store Connect API. Learn how you can manage more about your presence on the App Store with the App Metadata API, or use the new Power and Performance Metrics and Diagnostics API to access the same aggregate data that drives the Power and Performance analysis tools in Xcode. Whether you’re managing team members and provisioning profiles, adding or removing beta testers, or downloading your sales and financial reports, this comprehensive API makes automation of these processes a snap.",
"title": "Expanding automation with the App Store Connect API",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"keywords": [
"app store",
"automation",
"json",
"testflight"
],
"topicIds": [
39,
71,
69,
41,
40
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10004/5/7436A537-996F-4CD6-B553-9303BFB99348/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10004/5/7436A537-996F-4CD6-B553-9303BFB99348/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10004/5/7436A537-996F-4CD6-B553-9303BFB99348/transcripts/wwdc2020-10004-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10004/5/7436A537-996F-4CD6-B553-9303BFB99348/wwdc2020_10004_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10004/5/7436A537-996F-4CD6-B553-9303BFB99348/wwdc2020_10004_sd.mp4",
"duration": 1540
},
"related": {
"activities": [
"wwdc2020-10057",
"wwdc2020-10651",
"wwdc2020-10756",
"wwdc2020-10840",
"wwdc2018-303"
],
"resources": [
943,
942,
463,
462,
309
]
}
},
{
"id": "wwdc2020-10677",
"staticContentId": 3788,
"eventContentId": 10677,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10677",
"description": "Discover the Metal Performance Shaders (MPS) Graph, which extends Metal's Compute capabilities to multi-dimensional Tensors. MPS Graph builds on the highly tuned library of data parallel primitives that are vital to machine learning and leverages the tremendous power of the GPU. Explore how MPS Graph can help express sophisticated and dynamic neural network training architectures and optimize across them to get acceleration on the GPU.\r\n\r\nFor a deeper understanding of the concepts covered in this session, check out \"Metal for Machine Learning” from WWDC19.",
"title": "Build customized ML models with the Metal Performance Shaders Graph",
"originalPublishingDate": "2020-06-26T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS"
],
"keywords": [
"compute",
"graph",
"machine learning",
"metal",
"metal shading language",
"mps",
"mps graph",
"neural network",
"operations",
"tensors"
],
"topicIds": [
27,
16
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10677/2/C6396D39-7970-4E1A-A045-BC5A85B9AC36/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10677/2/C6396D39-7970-4E1A-A045-BC5A85B9AC36/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10677/2/C6396D39-7970-4E1A-A045-BC5A85B9AC36/transcripts/wwdc2020-10677-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10677/2/C6396D39-7970-4E1A-A045-BC5A85B9AC36/wwdc2020_10677_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10677/2/C6396D39-7970-4E1A-A045-BC5A85B9AC36/wwdc2020_10677_sd.mp4",
"duration": 2375
},
"related": {
"activities": [
"wwdc2020-10810",
"wwdc2020-10811",
"wwdc2020-10812",
"wwdc2020-10813",
"wwdc2019-614",
"wwdc2018-609",
"tech-talks-10858",
"wwdc2017-608"
],
"resources": [
896,
56,
38
]
}
},
{
"id": "wwdc2020-10114",
"staticContentId": 3781,
"eventContentId": 10114,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10114",
"description": "Apple silicon Macs can run many iPad and iPhone apps as-is, and these apps will be made available to users on the Mac through the Mac App Store. Discover how iPad and iPhone apps run on Apple silicon Macs, and the factors that make your apps come across better. Learn how to test your app for the Mac, and hear about your options for distribution of your apps.",
"title": "iPad and iPhone apps on Apple silicon Macs",
"originalPublishingDate": "2020-06-23T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS"
],
"keywords": [
"arm",
"emulator"
],
"topicIds": [
71,
38
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10114/4/6F739926-5C96-42A5-8EAC-176185E35089/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10114/4/6F739926-5C96-42A5-8EAC-176185E35089/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10114/4/6F739926-5C96-42A5-8EAC-176185E35089/transcripts/wwdc2020-10114-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10114/4/6F739926-5C96-42A5-8EAC-176185E35089/wwdc2020_10114_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10114/4/6F739926-5C96-42A5-8EAC-176185E35089/wwdc2020_10114_sd.mp4",
"duration": 1049
},
"related": {
"activities": [
"wwdc2020-10214",
"wwdc2019-205"
],
"resources": [
1291,
1290
]
}
},
{
"id": "wwdc2020-10216",
"staticContentId": 3763,
"eventContentId": 10216,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10216",
"description": "ResearchKit continues to simplify how developers build research and care apps. Explore how the latest ResearchKit updates expand the boundaries of data researchers can collect. Learn about features like enhanced onboarding, extended options for surveys, and new active tasks. Discover how Apple has partnered with the research community to leverage this framework, helping developers build game-changing apps that empower care teams and the research community.",
"title": "What's new in ResearchKit",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"watchOS"
],
"keywords": [
"activities",
"chart",
"graph",
"healthkit",
"study",
"task"
],
"topicIds": [
14
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "instructionStep",
"startTimeSeconds": 204,
"endTimeSeconds": 219,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e instructionStep = u003cspan class=\"syntax-type\"u003eORKInstructionStepu003c/spanu003e(identifier: u003cspan class=\"syntax-string\"u003e\"InstructionStepIdentifier\"u003c/spanu003e)\ninstructionStep.title = u003cspan class=\"syntax-string\"u003e\"Welcome!\"u003c/spanu003e\ninstructionStep.detailText = u003cspan class=\"syntax-string\"u003e\"Thank you for joining our study. Tap Next to learn more before signing up.\"u003c/spanu003e\ninstructionStep.image = u003cspan class=\"syntax-type\"u003eUIImageu003c/spanu003e(named: u003cspan class=\"syntax-string\"u003e\"health_blocks\"u003c/spanu003e)!"
},
{
"title": "informedConsentInstructionStep",
"startTimeSeconds": 248,
"endTimeSeconds": 276,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e informedConsentInstructionStep = u003cspan class=\"syntax-type\"u003eORKInstructionStepu003c/spanu003e(identifier: u003cspan class=\"syntax-string\"u003e\"ConsentStepIdentifier\"u003c/spanu003e)\ninformedConsentInstructionStep.title = u003cspan class=\"syntax-string\"u003e\"Before You Join\"u003c/spanu003e\ninformedConsentInstructionStep.image = u003cspan class=\"syntax-type\"u003eUIImageu003c/spanu003e(named: u003cspan class=\"syntax-string\"u003e\"informed_consent\"u003c/spanu003e)!\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e heartBodyItem = u003cspan class=\"syntax-type\"u003eORKBodyItemu003c/spanu003e(text: exampleText, \n detailText: u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e, \n image: u003cspan class=\"syntax-type\"u003eUIImageu003c/spanu003e(systemName: u003cspan class=\"syntax-string\"u003e\"heart.fill\"u003c/spanu003e), \n learnMoreItem: u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e, \n bodyItemStyle: .image)\n\ninformedConsentInstructionStep.bodyItems = [heartBodyItem]"
},
{
"title": "webViewStep",
"startTimeSeconds": 304,
"endTimeSeconds": 322,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e webViewStep = u003cspan class=\"syntax-type\"u003eORKWebViewStepu003c/spanu003e(identifier: u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e(describing: u003cspan class=\"syntax-type\"u003eIdentifieru003c/spanu003e.webViewStep), html: exampleHtml)\nwebViewStep.showSignatureAfterContent = u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e"
},
{
"title": "sesAnswerFormat",
"startTimeSeconds": 463,
"endTimeSeconds": 480,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e sesAnswerFormat = u003cspan class=\"syntax-type\"u003eORKSESAnswerFormatu003c/spanu003e(topRungText: u003cspan class=\"syntax-string\"u003e\"Optimal Health\"u003c/spanu003e, \n bottomRungText: u003cspan class=\"syntax-string\"u003e\"Poor Health\"u003c/spanu003e)\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e sesFormItem = u003cspan class=\"syntax-type\"u003eORKFormItemu003c/spanu003e(identifier: u003cspan class=\"syntax-string\"u003e\"sesIdentifier\"u003c/spanu003e, \n text: exampleText, \n answerFormat: sesAnswerFormat)"
},
{
"title": "scaleAnswerFormItem",
"startTimeSeconds": 527,
"endTimeSeconds": 550,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e scaleAnswerFormat = u003cspan class=\"syntax-type\"u003eORKScaleAnswerFormatu003c/spanu003e(maximumValue: u003cspan class=\"syntax-number\"u003e10u003c/spanu003e, minimumValue: u003cspan class=\"syntax-number\"u003e1u003c/spanu003e, defaultValue: u003cspan class=\"syntax-number\"u003e11u003c/spanu003e, step: u003cspan class=\"syntax-number\"u003e1u003c/spanu003e)\nscaleAnswerFormat.shouldShowDontKnowButton = u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e\nscaleAnswerFormat.customDontKnowButtonText = u003cspan class=\"syntax-string\"u003e\"Prefer not to answer\"u003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e scaleAnswerFormItem = u003cspan class=\"syntax-type\"u003eORKFormItemu003c/spanu003e(identifier: u003cspan class=\"syntax-string\"u003e\"ScaleAnswerFormItemIdentifier\"u003c/spanu003e, \n text: u003cspan class=\"syntax-string\"u003e\"What is your current pain level?\"u003c/spanu003e, \n answerFormat: scaleAnswerFormat)"
},
{
"title": "textAnswerQuestionStep",
"startTimeSeconds": 587,
"endTimeSeconds": 617,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e textAnswerFormat = u003cspan class=\"syntax-type\"u003eORKAnswerFormatu003c/spanu003e.textAnswerFormat()\ntextAnswerFormat.multipleLines = u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e\ntextAnswerFormat.maximumLength = u003cspan class=\"syntax-number\"u003e280u003c/spanu003e;\ntextAnswerFormat.hideWordCountLabel = u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e\ntextAnswerFormat.hideClearButton = u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e\n \nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e textAnswerQuestionStep = u003cspan class=\"syntax-type\"u003eORKQuestionStepu003c/spanu003e(identifier: textAnswerIdentifier),\n title: exampleTitle,\n question: exampleQuestionText,\n answer: textAnswerFormat)"
},
{
"title": "ORKReviewViewController",
"startTimeSeconds": 660,
"endTimeSeconds": 694,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e reviewVC = u003cspan class=\"syntax-type\"u003eORKReviewViewControlleru003c/spanu003e(task: taskViewController.task,\n result: taskViewController.result,\n delegate: u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e)\nreviewVC.reviewTitle = u003cspan class=\"syntax-string\"u003e\"Review your response\"u003c/spanu003e\nreviewVC.text = u003cspan class=\"syntax-string\"u003e\"Please take a moment to review your responses below. If you need to change any answers just tap the edit button to update your response.\"u003c/spanu003e"
},
{
"title": "ORK3DModelStep",
"startTimeSeconds": 870,
"endTimeSeconds": 908,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e usdzModelManager = u003cspan class=\"syntax-type\"u003eORKUSDZModelManageru003c/spanu003e(usdzFileName: u003cspan class=\"syntax-string\"u003e\"toy_drummer\"u003c/spanu003e)\nusdzModelManager.allowsSelection = u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e\nusdzModelManager.highlightColor = .yellow\nusdzModelManager.enableContinueAfterSelection = u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e\nusdzModelManager.identifiersOfObjectsToHighlight = arrayOfIdentifiers\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e threeDimensionalModelStep = u003cspan class=\"syntax-type\"u003eORK3DModelStepu003c/spanu003e(identifier: drummerModelIdentifier,\n modelManager: usdzModelManager)"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10216/5/10085282-EADD-4030-9CAF-5F5A1D28C4E7/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10216/5/10085282-EADD-4030-9CAF-5F5A1D28C4E7/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10216/3/67C0CCDC-EB59-439A-8067-6624165C331E/transcripts/wwdc2020-10216-transcripts.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10216/5/10085282-EADD-4030-9CAF-5F5A1D28C4E7/wwdc2020_10216_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10216/5/10085282-EADD-4030-9CAF-5F5A1D28C4E7/wwdc2020_10216_sd.mp4",
"duration": 1849
},
"related": {
"activities": [
"wwdc2020-10151",
"wwdc2020-10656",
"wwdc2020-10737",
"wwdc2020-10757"
],
"resources": [
1283,
1282,
745
]
}
},
{
"id": "wwdc2020-10904",
"staticContentId": 3815,
"eventContentId": 10904,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=xpew8919",
"description": "",
"title": "Create accessible apps",
"articleID": "21598204-01F4-4D2C-85EB-A0C2C706A7F4",
"articlePermalinkKey": "xpew8919",
"originalPublishingDate": "2020-06-22T13:27:23-07:00",
"publishingExpiryDate": "2025-06-22T14:04:36-07:00",
"topicIds": [
],
"type": "Article",
"images": [
"square",
"wide"
],
"related": {
"activities": [
"wwdc2020-10749",
"wwdc2020-10750",
"wwdc2020-10751"
]
}
},
{
"id": "wwdc2020-10194",
"staticContentId": 3643,
"eventContentId": 10194,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10194",
"description": "Widgets are at their best when they show up on someone’s Home screen or in the Today View at the right time and provide actionable, relevant information. We’ll show you how to build configurable widgets to let people create a personalized Home screen experience, and that take advantage of system intelligence to help people get what they want, when they want it. Learn how to customize your widget’s configuration interface, and how to appear within Siri Suggestions or at the top of a widget Smart Stack based on user behavior or by letting the system know when there's new, timely information.\r\n\r\nFor more on widgets, watch \"Meet WidgetKit\". And for more on system intelligence, watch the collection \"Design for Intelligence.\"",
"title": "Add configuration and intelligence to your widgets",
"originalPublishingDate": "2020-06-26T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS"
],
"keywords": [
"donations",
"intelligence",
"intelligent system experience",
"intents",
"proactive",
"shortcuts",
"stack intelligence",
"stacks",
"system intelligence",
"widget",
"widgetkit"
],
"topicIds": [
21,
13
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10194/2/F906ACBE-2D67-4594-B041-E1F11352CF3A/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10194/2/F906ACBE-2D67-4594-B041-E1F11352CF3A/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10194/2/F906ACBE-2D67-4594-B041-E1F11352CF3A/transcripts/wwdc2020-10194-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10194/2/F906ACBE-2D67-4594-B041-E1F11352CF3A/wwdc2020_10194_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10194/2/F906ACBE-2D67-4594-B041-E1F11352CF3A/wwdc2020_10194_sd.mp4",
"duration": 1652
},
"related": {
"activities": [
"wwdc2020-10028",
"wwdc2020-10035",
"wwdc2020-10036",
"wwdc2020-10068",
"wwdc2020-10069",
"wwdc2020-10086",
"wwdc2020-10087",
"wwdc2020-10088",
"wwdc2020-10200",
"wwdc2020-10203",
"wwdc2020-10879"
],
"resources": [
1213,
1212
]
}
},
{
"id": "wwdc2020-10014",
"staticContentId": 3811,
"eventContentId": 10014,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=tukbz962",
"description": "",
"title": "Core Image",
"articleID": "E6C66ECB-5F69-408C-AD76-9568410FEA8A",
"articlePermalinkKey": "tukbz962",
"originalPublishingDate": "2020-06-22T00:00:16-07:00",
"publishingExpiryDate": "2025-06-22T02:27:33-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS"
],
"keywords": [
"coreimage",
"core image",
"debugging",
"metal",
"performance",
"video",
"xcode"
],
"topicIds": [
38,
35,
31,
30,
27,
24
],
"type": "Article",
"images": [
"square",
"wide"
],
"related": {
"activities": [
"wwdc2020-10008",
"wwdc2020-10021",
"wwdc2020-10089",
"wwdc2020-10722",
"wwdc2020-10723"
]
}
},
{
"id": "wwdc2020-10798",
"staticContentId": 3819,
"eventContentId": 10798,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=bnqw62sc",
"description": "",
"title": "Create apps for a global audience",
"articleID": "03DC911E-2406-4F06-9F39-B5953CE22B63",
"articlePermalinkKey": "bnqw62sc",
"originalPublishingDate": "2020-06-22T05:46:56-07:00",
"publishingExpiryDate": "2025-06-22T05:50:19-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"keywords": [
"🌍",
"🌎",
"🌏",
"i18n",
"localization",
"world"
],
"topicIds": [
42
],
"type": "Article",
"related": {
"activities": [
"wwdc2020-10782",
"wwdc2020-10784"
]
}
},
{
"id": "wwdc2020-10211",
"staticContentId": 3820,
"eventContentId": 10211,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=g28d5j9l",
"description": "",
"title": "Move from kexts to system extensions",
"articleID": "B64F112A-EA8F-4480-890C-E23C188A801E",
"articlePermalinkKey": "g28d5j9l",
"originalPublishingDate": "2020-06-22T05:47:30-07:00",
"publishingExpiryDate": "2025-06-22T05:54:33-07:00",
"platforms": [
"macOS"
],
"keywords": [
"driver",
"kauth",
"kernel",
"security"
],
"topicIds": [
67,
19
],
"type": "Article",
"images": [
"wide"
],
"related": {
"activities": [
"wwdc2020-10159",
"wwdc2020-10210",
"wwdc2020-10778",
"wwdc2020-10779",
"wwdc2020-10899",
"wwdc2019-702"
]
}
},
{
"id": "wwdc2020-10686",
"staticContentId": 3880,
"eventContentId": 10686,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10686",
"description": "Discover how Macs with Apple silicon will deliver modern advantages using Apple's System-on-Chip (SoC) architecture. Leveraging a unified memory architecture for CPU and GPU tasks, Mac apps will see amazing performance benefits from Apple silicon tuned frameworks such as Metal and Accelerate. Learn about new features and changes coming to boot and security, and how these may affect your applications.",
"title": "Explore the new system architecture of Apple silicon Macs",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"macOS"
],
"keywords": [
"amp",
"apple silicon",
"apple silicon mac",
"asymmetric multiprocessing",
"driverkit",
"macos recovery",
"mac sharing mode",
"reduced security",
"rosetta",
"secure boot",
"soc",
"system recovery"
],
"topicIds": [
35,
67
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Set up DMA transfer in a PCIe driver",
"startTimeSeconds": 582,
"endTimeSeconds": 608,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Get the IOMapper for the deviceu003c/spanu003e\nu003cspan class=\"syntax-type\"u003eIOMapperu003c/spanu003e *mapper = u003cspan class=\"syntax-type\"u003eIOMapperu003c/spanu003e::copyMapperForDevice(device);\n\nu003cspan class=\"syntax-comment\"u003e// Use an IODMACommand; pass the mapper when initializingu003c/spanu003e\nu003cspan class=\"syntax-type\"u003eIODMACommandu003c/spanu003e *dmaCommand = u003cspan class=\"syntax-type\"u003eIODMACommandu003c/spanu003e::withSpecification(\n outSegFunc, numAddressBits, maxSegmentSize, mappingOptions,\n maxTransferSize, alignment, mapper, refCon);\n\nu003cspan class=\"syntax-comment\"u003e// Keep the IODMACommand prepared for the duration of the i/ou003c/spanu003e"
},
{
"title": "Check if running in Rosetta",
"startTimeSeconds": 871,
"endTimeSeconds": 881,
"language": "objectivec",
"code": "u003cspan class=\"syntax-comment\"u003e// Use \"sysctl.proc_translated\" to check if running in Rosettau003c/spanu003e\n\nu003cspan class=\"syntax-comment\"u003e// Returns 1 if running in Rosettau003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eintu003c/spanu003e processIsTranslated() {\n u003cspan class=\"syntax-keyword\"u003eintu003c/spanu003e ret = u003cspan class=\"syntax-number\"u003e0u003c/spanu003e;\n size_t size = u003cspan class=\"syntax-keyword\"u003esizeofu003c/spanu003e(ret);\n\n u003cspan class=\"syntax-comment\"u003e// Call the sysctl and if successful return the resultu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e (sysctlbyname(u003cspan class=\"syntax-string\"u003e\"sysctl.proc_translated\"u003c/spanu003e, u0026amp;ret, u0026amp;size, u003cspan class=\"syntax-literal\"u003eNULLu003c/spanu003e, u003cspan class=\"syntax-number\"u003e0u003c/spanu003e) != u003cspan class=\"syntax-number\"u003e-1u003c/spanu003e) \n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e ret;\n\n u003cspan class=\"syntax-comment\"u003e// If \"sysctl.proc_translated\" is not present then must be nativeu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e (errno == ENOENT)\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-number\"u003e0u003c/spanu003e;\n\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-number\"u003e-1u003c/spanu003e;\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10686/4/63FE46AD-053B-4294-B04F-A4BE576BD265/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10686/4/63FE46AD-053B-4294-B04F-A4BE576BD265/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10686/4/63FE46AD-053B-4294-B04F-A4BE576BD265/transcripts/wwdc2020-10686-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10686/4/63FE46AD-053B-4294-B04F-A4BE576BD265/wwdc2020_10686_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10686/4/63FE46AD-053B-4294-B04F-A4BE576BD265/wwdc2020_10686_sd.mp4",
"duration": 1396
},
"related": {
"activities": [
"wwdc2020-10214",
"wwdc2020-10632",
"articles-10234"
],
"resources": [
1333,
1332
]
}
},
{
"id": "wwdc2020-10084",
"staticContentId": 3514,
"eventContentId": 10084,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10084",
"description": "Learn foolproof ways to surface your app’s actions in the Shortcuts app — and help people quickly set up powerful, personalized shortcuts using system intelligence. We’ll detail how to configure your intents to appear in the new Automation Suggestions, explore how the system surfaces your app's actions for people based on their everyday app usage, and show you how you can make sure your app appears in all the right places within the Shortcuts app.",
"title": "Feature your actions in the Shortcuts app",
"originalPublishingDate": "2020-06-26T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"watchOS"
],
"keywords": [
"intents",
"intentsui",
"shortcuts",
"shortcuts app",
"siri",
"sirikit"
],
"topicIds": [
21,
13
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10084/4/E5265AB0-710D-4449-B77E-B49C282280C3/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10084/4/E5265AB0-710D-4449-B77E-B49C282280C3/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10084/4/E5265AB0-710D-4449-B77E-B49C282280C3/transcripts/wwdc2020-10084-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10084/4/E5265AB0-710D-4449-B77E-B49C282280C3/wwdc2020_10084_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10084/4/E5265AB0-710D-4449-B77E-B49C282280C3/wwdc2020_10084_sd.mp4",
"duration": 609
},
"related": {
"activities": [
"wwdc2020-10053",
"wwdc2020-10060",
"wwdc2020-10061",
"wwdc2020-10068",
"wwdc2020-10069",
"wwdc2020-10071",
"wwdc2020-10073",
"wwdc2020-10074",
"wwdc2020-10083",
"wwdc2020-10086",
"wwdc2020-10088",
"wwdc2020-10190",
"wwdc2020-10200",
"wwdc2020-10203",
"wwdc2020-10839",
"wwdc2020-10877",
"wwdc2020-10878",
"wwdc2020-10914",
"wwdc2020-10917",
"wwdc2020-10963"
],
"resources": [
1113,
1112
]
}
},
{
"id": "wwdc2020-10005",
"staticContentId": 3335,
"eventContentId": 10005,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10005",
"description": "It’s now easier than ever to deliver academic tests on the Mac. Learn how education developers can leverage the Automatic Assessment Configuration framework for iPhone, iPad, and Mac to deliver tests and assess students across all devices. And discover how developers can enable restricted features within tests and exams on iOS to accommodate student needs or suit the test content.",
"title": "What's new in assessment",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS"
],
"keywords": [
"assessment",
"catalyst",
"curriculum",
"education",
"student",
"testing"
],
"topicIds": [
19,
12
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Working with AAC",
"startTimeSeconds": 231,
"endTimeSeconds": 414,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e AutomaticAssessmentConfiguration\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eAssessmentManageru003c/spanu003e: u003cspan class=\"syntax-title\"u003eNSObjectu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003eprivateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e assessmentSession: u003cspan class=\"syntax-type\"u003eAEAssessmentSession?u003c/spanu003e\n \n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ebeginAssessmentModeu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e config = u003cspan class=\"syntax-type\"u003eAEAssessmentConfigurationu003c/spanu003e() u003cspan class=\"syntax-comment\"u003e// Configure AAC behavioru003c/spanu003e\n \n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e session = u003cspan class=\"syntax-type\"u003eAEAssessmentSessionu003c/spanu003e(configuration: config) u003cspan class=\"syntax-comment\"u003e// Construct your sessionu003c/spanu003e\n \n session.delegate = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e u003cspan class=\"syntax-comment\"u003e// Receive lifecycle events via delegationu003c/spanu003e\n \n assessmentSession = session u003cspan class=\"syntax-comment\"u003e// Retain the sessionu003c/spanu003e\n \n u003cspan class=\"syntax-comment\"u003e// Present assessment mode bringup transition UIu003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// ...u003c/spanu003e\n \n session.begin()\n }\n \n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eendAssessmentModeu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e session = assessmentSession u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e\n }\n \n u003cspan class=\"syntax-comment\"u003e// Present assessment mode teardown transition UIu003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// ...u003c/spanu003e\n \n session.end()\n }\n}\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eextensionu003c/spanu003e u003cspan class=\"syntax-title\"u003eAssessmentManageru003c/spanu003e: u003cspan class=\"syntax-title\"u003eAEAssessmentSessionDelegateu003c/spanu003e u003c/spanu003e{\n \n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eassessmentSessionDidBeginu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e session: AEAssessmentSession)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Stop showing assessment mode bringup transition UIu003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// ...u003c/spanu003e\n \n u003cspan class=\"syntax-comment\"u003e// Present sensitive testing contentu003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// ...u003c/spanu003e\n }\n \n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eassessmentSessionu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e session: AEAssessmentSession, failedToBeginWithError error: Error)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Stop showing assessment mode bringup transition UIu003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// ...u003c/spanu003e\n\n u003cspan class=\"syntax-comment\"u003e// Present some kind of error UIu003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// ...u003c/spanu003e\n \n u003cspan class=\"syntax-comment\"u003e// Release your reference to the AEAssessmentSessionu003c/spanu003e\n assessmentSession = u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e\n }\n \n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eassessmentSessionDidEndu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e session: AEAssessmentSession)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Stop showing assessment mode teardown transition UIu003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// ...u003c/spanu003e\n \n u003cspan class=\"syntax-comment\"u003e// Present your post-test UIu003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// (maybe a result, a confirmation, or just the initial view)u003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// ...u003c/spanu003e\n \n u003cspan class=\"syntax-comment\"u003e// Release your reference to the AEAssessmentSessionu003c/spanu003e\n assessmentSession = u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e\n }\n \n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eassessmentSessionu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e session: AEAssessmentSession, wasInterruptedWithError error: Error)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Hide all sensitive UIu003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// ...u003c/spanu003e\n \n u003cspan class=\"syntax-comment\"u003e// Present some kind of error UIu003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// ...u003c/spanu003e\n \n session.end()\n }\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10005/3/50CEFA81-2D73-4ACC-B274-399608A1BAAF/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10005/3/50CEFA81-2D73-4ACC-B274-399608A1BAAF/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10005/3/50CEFA81-2D73-4ACC-B274-399608A1BAAF/transcripts/wwdc2020-10005-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10005/3/50CEFA81-2D73-4ACC-B274-399608A1BAAF/wwdc2020_10005_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10005/3/50CEFA81-2D73-4ACC-B274-399608A1BAAF/wwdc2020_10005_sd.mp4",
"duration": 767
},
"related": {
"activities": [
"wwdc2020-10658",
"wwdc2020-10753",
"wwdc2020-10754",
"wwdc2020-10844"
],
"resources": [
935,
934,
777
]
}
},
{
"id": "wwdc2020-10636",
"staticContentId": 3680,
"eventContentId": 10636,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10636",
"description": "Deliver a smooth streaming audio experience straight to the wrist. We’ll talk about some of the new things for building great streaming apps unique to Apple Watch. Learn how to integrate more audio formats, deliver streams more efficiently through new codecs, and add encrypted content to expand your app’s media library.\r\n\r\nThis session builds on techniques introduced in “Streaming Audio on watchOS 6” from WWDC19. If you’re new to audio on Apple Watch, we recommend you watch that video for a primer.",
"title": "What's new in streaming audio for Apple Watch",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"watchOS"
],
"topicIds": [
28
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10636/5/9930A39B-629C-4BD8-A16B-4516BC60E872/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10636/5/9930A39B-629C-4BD8-A16B-4516BC60E872/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10636/4/9B21455F-1B4A-4C94-B227-4C05DFBF618C/transcripts/wwdc2020-10636-transcripts.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10636/5/9930A39B-629C-4BD8-A16B-4516BC60E872/wwdc2020_10636_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10636/5/9930A39B-629C-4BD8-A16B-4516BC60E872/wwdc2020_10636_sd.mp4",
"duration": 432
},
"related": {
"activities": [
"wwdc2020-10158",
"wwdc2020-10847",
"wwdc2020-10851",
"wwdc2019-716",
"wwdc2018-504",
"wwdc2018-507"
],
"resources": [
1233,
1232
]
}
},
{
"id": "wwdc2020-10693",
"staticContentId": 3887,
"eventContentId": 10693,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10693",
"description": "What a Wednesday! Let us catch you up on the day’s sessions and find out what you can expect from the day ahead.",
"title": "Wednesday@WWDC",
"originalPublishingDate": "2020-06-24T22:00:00-07:00",
"publishingExpiryDate": "2022-06-22T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"keywords": [
"daily",
"daily recap",
"highlights",
"highlights monday",
"recap",
"wwdc",
"wwdc20",
"wwdc recap",
"wwdc wednesday",
"wwdc weds"
],
"topicIds": [
1
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10693/5/6AE2C343-800F-4D53-AA3B-B66B82E54FEE/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10693/5/6AE2C343-800F-4D53-AA3B-B66B82E54FEE/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10693/5/6AE2C343-800F-4D53-AA3B-B66B82E54FEE/transcripts/wwdc2020-10693-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10693/5/6AE2C343-800F-4D53-AA3B-B66B82E54FEE/wwdc2020_10693_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10693/5/6AE2C343-800F-4D53-AA3B-B66B82E54FEE/wwdc2020_10693_sd.mp4",
"duration": 89
},
"related": {
"activities": [
"wwdc2020-10006",
"wwdc2020-10031",
"wwdc2020-10033",
"wwdc2020-10034",
"wwdc2020-10037",
"wwdc2020-10047",
"wwdc2020-10056",
"wwdc2020-10060",
"wwdc2020-10086",
"wwdc2020-10099",
"wwdc2020-10100",
"wwdc2020-10151",
"wwdc2020-10168",
"wwdc2020-10207",
"wwdc2020-10617",
"wwdc2020-10652",
"wwdc2020-10673",
"wwdc2020-10691",
"wwdc2020-10692",
"wwdc2020-10694",
"wwdc2020-10695"
]
}
},
{
"id": "wwdc2020-10034",
"staticContentId": 3572,
"eventContentId": 10034,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10034",
"description": "Take your app on a most wondrous adventure to the home and Today screens of iPhone, iPad, and Mac. Grab the starter project and code along with us! We will guide you through the process of creating a widget for your app from start to finish so that you can provide people with beautiful views and glanceable information in an easily-accessible place. Discover how to create a widget project, learn fundamental concepts for widgets and their structure, configure the widget and its provider, and start exploring timeline concepts.\r\n\r\nOnce you’re finished, travel onward with us to part two of the Widgets Code-along where we’ll learn more about timelines, system intelligence, and configuration.",
"title": "Widgets Code-along, part 1: The adventure begins",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS"
],
"keywords": [
"codealong",
"code-along",
"placeholder",
"previews",
"swiftui",
"timeline",
"view",
"widget",
"widget family",
"widgetkit",
"widget target"
],
"topicIds": [
36,
22,
13
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10034/3/D86D9B81-6A8A-4015-86B1-7784AB7B3731/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10034/3/D86D9B81-6A8A-4015-86B1-7784AB7B3731/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10034/3/D86D9B81-6A8A-4015-86B1-7784AB7B3731/transcripts/wwdc2020-10034-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10034/3/D86D9B81-6A8A-4015-86B1-7784AB7B3731/wwdc2020_10034_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10034/3/D86D9B81-6A8A-4015-86B1-7784AB7B3731/wwdc2020_10034_sd.mp4",
"duration": 545
},
"related": {
"activities": [
"wwdc2020-10028",
"wwdc2020-10033",
"wwdc2020-10035",
"wwdc2020-10036",
"wwdc2020-10041",
"wwdc2020-10103",
"wwdc2020-10693"
],
"resources": [
1157,
1156,
810
]
}
},
{
"id": "wwdc2020-10792",
"staticContentId": 3808,
"eventContentId": 10792,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=ytff2mfz",
"description": "",
"title": "Explore Swan’s Quest",
"articleID": "B7B36E03-3E05-432F-83D2-3F3DFC1C0191",
"articlePermalinkKey": "ytff2mfz",
"originalPublishingDate": "2020-06-22T11:40:30-07:00",
"publishingExpiryDate": "2025-06-22T05:25:30-07:00",
"platforms": [
"iOS",
"macOS"
],
"topicIds": [
],
"type": "Article",
"images": [
"square",
"wide"
],
"related": {
"activities": [
"wwdc2020-10654"
]
}
},
{
"id": "wwdc2020-10031",
"staticContentId": 3455,
"eventContentId": 10031,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10031",
"description": "Display detailed data in your SwiftUI apps more quickly and efficiently with improved stacks and new list and outline views. Now available on iOS and iPadOS for the first time, outlines are a new multi-platform tool for expressing hierarchical data that work alongside stacks and lists. Learn how to use new and improved tools in SwiftUI to display more content on screen when using table views, create smooth-scrolling and responsive stacks, and build out list views for content that needs more than a vStack can provide. Take your layout options even further with the new grid view, as well as disclosure groups.\r\n\r\nTo get the most out of this video, we recommend first checking out “SwiftUI App Essentials,” which provides an overview of everything new in SwiftUI for 2020. If you’re brand-new to coding with SwiftUI, we also suggest watching 2019’s “SwiftUI Essentials” talk.",
"title": "Stacks, Grids, and Outlines in SwiftUI",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"keywords": [
"children key path",
"disclosuregroup",
"disclosure groups",
"disclosure triangle",
"forms",
"griditem",
"group",
"hierarchical data",
"hstack",
"isexpanded",
"label",
"layout primitives",
"lazygrid",
"lazyhgrid",
"lazyhstack",
"lazyvgrid",
"lazyvstack",
"liststyle",
"outlinegroup",
"outline groups",
"scrolling",
"selection",
"sidebar",
"tree structure data",
"vstack"
],
"topicIds": [
36,
22
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Sandwich and HeroView",
"startTimeSeconds": 128,
"endTimeSeconds": 145,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Sandwich model and gallery item viewu003c/spanu003e\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eSandwichu003c/spanu003e: u003cspan class=\"syntax-title\"u003eIdentifiableu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e id = u003cspan class=\"syntax-type\"u003eUUIDu003c/spanu003e()\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e name: u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e rating: u003cspan class=\"syntax-type\"u003eIntu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e heroImage: u003cspan class=\"syntax-type\"u003eImageu003c/spanu003e { … }\n}\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eHeroViewu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e sandwich: u003cspan class=\"syntax-type\"u003eSandwichu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n sandwich.heroImage\n .resizable()\n .aspectRatio(contentMode: .fit)\n .overlay(u003cspan class=\"syntax-type\"u003eBannerViewu003c/spanu003e(sandwich: sandwich))\n }\n}"
},
{
"title": "Sandwich Info Banner",
"startTimeSeconds": 146,
"endTimeSeconds": 153,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Banner overlay view for sandwich infou003c/spanu003e\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eBannerViewu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e sandwich: u003cspan class=\"syntax-type\"u003eSandwichu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eVStacku003c/spanu003e(alignment: .leading, spacing: u003cspan class=\"syntax-number\"u003e10u003c/spanu003e) {\n u003cspan class=\"syntax-type\"u003eSpaceru003c/spanu003e()\n u003cspan class=\"syntax-type\"u003eTitleViewu003c/spanu003e(title: sandwich.name)\n u003cspan class=\"syntax-type\"u003eRatingViewu003c/spanu003e(rating: sandwich.rating)\n }\n .padding(…)\n .background(…)\n }\n}"
},
{
"title": "Sandwich Rating View",
"startTimeSeconds": 154,
"endTimeSeconds": 158,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Sandwich rating viewu003c/spanu003e\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eRatingViewu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e rating: u003cspan class=\"syntax-type\"u003eIntu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eHStacku003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eForEachu003c/spanu003e(u003cspan class=\"syntax-number\"u003e0u003c/spanu003e..u0026lt;u003cspan class=\"syntax-number\"u003e5u003c/spanu003e) { starIndex u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-type\"u003eStarImageu003c/spanu003e(isFilled: rating u0026gt; starIndex)\n }\n u003cspan class=\"syntax-type\"u003eSpaceru003c/spanu003e()\n }\n }\n}"
},
{
"title": "Scrollable Stack of HeroViews",
"startTimeSeconds": 159,
"endTimeSeconds": 196,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Fetch sandwiches from the sandwich storeu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e sandwiches: [u003cspan class=\"syntax-type\"u003eSandwichu003c/spanu003e] = …\n\nu003cspan class=\"syntax-type\"u003eScrollViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eVStacku003c/spanu003e(spacing: u003cspan class=\"syntax-number\"u003e0u003c/spanu003e) {\n u003cspan class=\"syntax-type\"u003eForEachu003c/spanu003e(sandwiches) { sandwich u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-type\"u003eHeroViewu003c/spanu003e(sandwich: sandwich)\n }\n }\n}"
},
{
"title": "Scrollable Stack of HeroViews",
"startTimeSeconds": 233,
"endTimeSeconds": 236,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Fetch sandwiches from the sandwich storeu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e sandwiches: [u003cspan class=\"syntax-type\"u003eSandwichu003c/spanu003e] = …\n\nu003cspan class=\"syntax-type\"u003eScrollViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eVStacku003c/spanu003e(spacing: u003cspan class=\"syntax-number\"u003e0u003c/spanu003e) {\n u003cspan class=\"syntax-type\"u003eForEachu003c/spanu003e(sandwiches) { sandwich u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-type\"u003eHeroViewu003c/spanu003e(sandwich: sandwich)\n }\n }\n}"
},
{
"title": "Scrollable Lazy Stack of HeroViews",
"startTimeSeconds": 237,
"endTimeSeconds": 300,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Fetch sandwiches from the sandwich storeu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e sandwiches: [u003cspan class=\"syntax-type\"u003eSandwichu003c/spanu003e] = …\n\nu003cspan class=\"syntax-type\"u003eScrollViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eLazyVStacku003c/spanu003e(spacing: u003cspan class=\"syntax-number\"u003e0u003c/spanu003e) {\n u003cspan class=\"syntax-type\"u003eForEachu003c/spanu003e(sandwiches) { sandwich u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-type\"u003eHeroViewu003c/spanu003e(sandwich: sandwich)\n }\n }\n}"
},
{
"title": "Scrollable Lazy Stack of HeroViews",
"startTimeSeconds": 369,
"endTimeSeconds": 377,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Fetch sandwiches from the sandwich storeu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e sandwiches: [u003cspan class=\"syntax-type\"u003eSandwichu003c/spanu003e] = …\n\nu003cspan class=\"syntax-type\"u003eScrollViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eLazyVStacku003c/spanu003e(spacing: u003cspan class=\"syntax-number\"u003e0u003c/spanu003e) {\n u003cspan class=\"syntax-type\"u003eForEachu003c/spanu003e(sandwiches) { sandwich u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-type\"u003eHeroViewu003c/spanu003e(sandwich: sandwich)\n }\n }\n}"
},
{
"title": "Three-Column Grid of Sandwiches",
"startTimeSeconds": 378,
"endTimeSeconds": 432,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Fetch sandwiches from the sandwich storeu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e sandwiches: [u003cspan class=\"syntax-type\"u003eSandwichu003c/spanu003e] = …\n\nu003cspan class=\"syntax-comment\"u003e// Define grid columnsu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e columns = [\n u003cspan class=\"syntax-type\"u003eGridItemu003c/spanu003e(spacing: u003cspan class=\"syntax-number\"u003e0u003c/spanu003e),\n u003cspan class=\"syntax-type\"u003eGridItemu003c/spanu003e(spacing: u003cspan class=\"syntax-number\"u003e0u003c/spanu003e),\n u003cspan class=\"syntax-type\"u003eGridItemu003c/spanu003e(spacing: u003cspan class=\"syntax-number\"u003e0u003c/spanu003e)\n]\n\nu003cspan class=\"syntax-type\"u003eScrollViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eLazyVGridu003c/spanu003e(columns: columns, spacing: u003cspan class=\"syntax-number\"u003e0u003c/spanu003e) {\n u003cspan class=\"syntax-type\"u003eForEachu003c/spanu003e(sandwiches) { sandwich u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-type\"u003eHeroViewu003c/spanu003e(sandwich: sandwich)\n }\n }\n}"
},
{
"title": "Adaptive Grid of Sandwiches",
"startTimeSeconds": 433,
"endTimeSeconds": 448,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Fetch sandwiches from the sandwich storeu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e sandwiches: [u003cspan class=\"syntax-type\"u003eSandwichu003c/spanu003e] = …\n\nu003cspan class=\"syntax-comment\"u003e// Define grid columnsu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e columns = [\n u003cspan class=\"syntax-type\"u003eGridItemu003c/spanu003e(.adaptive(minimum: u003cspan class=\"syntax-number\"u003e300u003c/spanu003e), spacing: u003cspan class=\"syntax-number\"u003e0u003c/spanu003e)\n]\n\nu003cspan class=\"syntax-type\"u003eScrollViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eLazyVGridu003c/spanu003e(columns: columns, spacing: u003cspan class=\"syntax-number\"u003e0u003c/spanu003e) {\n u003cspan class=\"syntax-type\"u003eForEachu003c/spanu003e(sandwiches) { sandwich u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-type\"u003eHeroViewu003c/spanu003e(sandwich: sandwich)\n }\n }\n}"
},
{
"title": "Outline of GraphicRows",
"startTimeSeconds": 527,
"endTimeSeconds": 544,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eGraphicsListu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e graphics: [u003cspan class=\"syntax-type\"u003eGraphicu003c/spanu003e]\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eListu003c/spanu003e(\n graphics,\n children: \\.children\n ) { graphic u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-type\"u003eGraphicRowu003c/spanu003e(graphic)\n }\n .listStyle(u003cspan class=\"syntax-type\"u003eSidebarListStyleu003c/spanu003e())\n }\n}"
},
{
"title": "Customizing your outlines",
"startTimeSeconds": 592,
"endTimeSeconds": 769,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Customizing your outlinesu003c/spanu003e\n\nu003cspan class=\"syntax-type\"u003eListu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eForEachu003c/spanu003e(canvases) { canvas u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-type\"u003eSectionu003c/spanu003e(header: u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(canvas.name)) {\n u003cspan class=\"syntax-type\"u003eOutlineGroupu003c/spanu003e(canvas.graphics, children: \\.children)\n { graphic u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-type\"u003eGraphicRowu003c/spanu003e(graphic)\n }\n }\n }\n}"
},
{
"title": "DisclosureGroup",
"startTimeSeconds": 790,
"endTimeSeconds": 806,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Progressive display of informationu003c/spanu003e\nu003cspan class=\"syntax-type\"u003eFormu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eDisclosureGroupu003c/spanu003e(isExpanded: $areFillControlsShowing) {\n u003cspan class=\"syntax-type\"u003eToggleu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Fill shape?\"u003c/spanu003e, isOn: isFilled)\n u003cspan class=\"syntax-type\"u003eColorRowu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Fill color\"u003c/spanu003e, color: fillColor)\n } label: {\n u003cspan class=\"syntax-type\"u003eLabelu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Fill\"u003c/spanu003e, …)\n }\n …\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10031/4/CC07F299-2B37-486D-9BA2-F305684689A2/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10031/4/CC07F299-2B37-486D-9BA2-F305684689A2/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10031/4/CC07F299-2B37-486D-9BA2-F305684689A2/transcripts/wwdc2020-10031-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10031/4/CC07F299-2B37-486D-9BA2-F305684689A2/wwdc2020_10031_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10031/4/CC07F299-2B37-486D-9BA2-F305684689A2/wwdc2020_10031_sd.mp4",
"duration": 1148
},
"related": {
"activities": [
"wwdc2020-10037",
"wwdc2020-10040",
"wwdc2020-10041",
"wwdc2020-10693",
"wwdc2020-10694",
"wwdc2020-10699",
"wwdc2020-10700",
"wwdc2020-10701",
"wwdc2019-216"
],
"resources": [
1055,
1054,
916
]
}
},
{
"id": "wwdc2020-10109",
"staticContentId": 3590,
"eventContentId": 10109,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10109",
"description": "When people use hardware keyboards with your app, they’re not only getting a more tactile and familiar typing experience — they can quickly navigate or use keyboard shortcuts, too. Discover how you can best support hardware keyboards for your iPadOS and Mac Catalyst apps: We’ll demystify the responder chain and show you best practices for implementing custom keyboard shortcuts. Learn how easy it is to get up and running with common system keyboard shortcuts, use modifier flags with gesture recognizers, and leverage the raw keyboard event API to respond to key down and key up events.",
"title": "Support hardware keyboards in your app",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS"
],
"keywords": [
"accelerators",
"event",
"magic keyboard",
"menu",
"shortcuts",
"text",
"uieventtype",
"uitextinput"
],
"topicIds": [
22,
9
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "PlayerViewController",
"startTimeSeconds": 1,
"endTimeSeconds": 2,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003ePlayerViewControlleru003c/spanu003e: u003cspan class=\"syntax-title\"u003eUIViewControlleru003c/spanu003e u003c/spanu003e{\n\n u003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e canBecomeFirstResponder: u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e \n }\n\n u003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eviewDidAppearu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e animated: Bool)u003c/spanu003eu003c/spanu003e {\n becomeFirstResponder()\n }\n\n u003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e keyCommands: [u003cspan class=\"syntax-type\"u003eUIKeyCommandu003c/spanu003e]? {\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e [\n u003cspan class=\"syntax-type\"u003eUIKeyCommandu003c/spanu003e(title: u003cspan class=\"syntax-type\"u003eNSLocalizedStringu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"PLAY_PAUSE\"u003c/spanu003e, comment: u003cspan class=\"syntax-string\"u003e\"…\"u003c/spanu003e),\n action: #selector(playPause),\n input: u003cspan class=\"syntax-string\"u003e\" \"u003c/spanu003e)\n ]\n }\n}"
},
{
"title": "SongListTableViewController",
"startTimeSeconds": 2,
"endTimeSeconds": 3,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eSongListTableViewControlleru003c/spanu003e: u003cspan class=\"syntax-title\"u003eUITableViewControlleru003c/spanu003e u003c/spanu003e{\n\n u003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e canBecomeFirstResponder: u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e\n }\n \n u003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eviewDidAppearu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e animated: Bool)u003c/spanu003eu003c/spanu003e {\n becomeFirstResponder()\n }\n \n u003cspan class=\"syntax-comment\"u003e/* UIResponderStandardEditActions */u003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eselectAllu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e sender: u003cspan class=\"syntax-keyword\"u003eAnyu003c/spanu003e?)u003c/spanu003eu003c/spanu003e { … }\n\n u003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ecopyu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e sender: u003cspan class=\"syntax-keyword\"u003eAnyu003c/spanu003e?)u003c/spanu003eu003c/spanu003e { … }\n\n u003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003epasteu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e sender: u003cspan class=\"syntax-keyword\"u003eAnyu003c/spanu003e?)u003c/spanu003eu003c/spanu003e { … }\n\n}"
},
{
"title": "UIKeyCommand",
"startTimeSeconds": 3,
"endTimeSeconds": 4,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eUIKeyCommandu003c/spanu003e : u003cspan class=\"syntax-title\"u003eUICommandu003c/spanu003e u003c/spanu003e{\n ...\n}\n\nu003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ebuildMenuu003c/spanu003eu003cspan class=\"syntax-params\"u003e(with builder: UIMenuBuilder)u003c/spanu003eu003c/spanu003e {\n builder.replaceChildren(ofMenu: .file) { children u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e [ u003cspan class=\"syntax-type\"u003eUIKeyCommandu003c/spanu003e() ] + children\n }\n}"
},
{
"title": "Extending selection with keyboard",
"startTimeSeconds": 4,
"endTimeSeconds": 5,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eoptionalu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003etableViewu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e tableView: UITableView,\n shouldBeginMultipleSelectionInteractionAt indexPath: IndexPath)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eoptionalu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003etableViewu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e tableView: UITableView,\n didBeginMultipleSelectionInteractionAt indexPath: IndexPath)u003c/spanu003eu003c/spanu003e"
},
{
"title": "recognizedDragGesture",
"startTimeSeconds": 5,
"endTimeSeconds": 6,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003erecognizedDragGestureu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e panGesture: UIPanGestureRecognizer)u003c/spanu003eu003c/spanu003e {\n\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e panGesture.modifierFlags.u003cspan class=\"syntax-built_in\"u003econtainsu003c/spanu003e(.command) {\n snapToGrid = u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e\n } u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e panGesture.modifierFlags.u003cspan class=\"syntax-built_in\"u003econtainsu003c/spanu003e(.shift) {\n constrainAspectRatio = u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e\n }\n \n ...\n}"
},
{
"title": "Responding to raw keyboard events",
"startTimeSeconds": 6,
"endTimeSeconds": 7,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eUIResponderu003c/spanu003e: u003cspan class=\"syntax-title\"u003eNSObjectu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003epressesBeganu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e presses: Setu0026lt;UIPressu0026gt;,\n with event: UIPressesEvent)u003c/spanu003eu003c/spanu003e\n \n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003epressesEndedu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e presses: Setu0026lt;UIPressu0026gt;,\n with event: UIPressesEvent)u003c/spanu003eu003c/spanu003e\n}"
},
{
"title": "CanvasViewController",
"startTimeSeconds": 7,
"endTimeSeconds": 8,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eCanvasViewControlleru003c/spanu003e: u003cspan class=\"syntax-title\"u003eUIViewControlleru003c/spanu003e u003c/spanu003e{\n \n u003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003epressesBeganu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e presses: Setu0026lt;UIPressu0026gt;, with event: UIPressesEvent?)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e press u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e presses {\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e key = press.key u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e { u003cspan class=\"syntax-keyword\"u003econtinueu003c/spanu003e }\n u003cspan class=\"syntax-keyword\"u003eswitchu003c/spanu003e key.keyCode {\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .keyboardUpArrow: startMoveUp()\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .keyboardDownArrow: startMoveDown()\n …\n }\n }\n }\n\n u003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003epressesEndedu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e presses: Setu0026lt;UIPressu0026gt;, with event: UIPressesEvent?)u003c/spanu003eu003c/spanu003e {\n stopMoving()\n }\n\n}"
},
{
"title": "CanvasViewController modifier flags",
"startTimeSeconds": 8,
"endTimeSeconds": 9,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eCanvasViewControlleru003c/spanu003e: u003cspan class=\"syntax-title\"u003eUIViewControlleru003c/spanu003e u003c/spanu003e{\n\n u003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003epressesBeganu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e presses: Setu0026lt;UIPressu0026gt;, with event: UIPressesEvent?)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e selectWhileMoving = u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e press u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e presses {\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e key = press.key u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e { u003cspan class=\"syntax-keyword\"u003econtinueu003c/spanu003e }\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e key.modifierFlags.u003cspan class=\"syntax-built_in\"u003econtainsu003c/spanu003e(.shift) {\n selectWhileMoving = u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e\n }\n \n u003cspan class=\"syntax-keyword\"u003eswitchu003c/spanu003e key.keyCode {\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .keyboardUpArrow: startMoveUp()\n \n }\n }\n }\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10109/2/B152D3FD-187C-4D34-80ED-152B996E5F6D/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10109/2/B152D3FD-187C-4D34-80ED-152B996E5F6D/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10109/2/B152D3FD-187C-4D34-80ED-152B996E5F6D/transcripts/wwdc2020-10109-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10109/2/B152D3FD-187C-4D34-80ED-152B996E5F6D/wwdc2020_10109_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10109/2/B152D3FD-187C-4D34-80ED-152B996E5F6D/wwdc2020_10109_sd.mp4",
"duration": 694
},
"related": {
"activities": [
"wwdc2020-10094",
"wwdc2020-10106",
"wwdc2020-10143",
"wwdc2020-10617",
"wwdc2019-224",
"wwdc2019-235",
"wwdc2017-242"
],
"resources": [
1179,
1178,
898,
793
]
}
},
{
"id": "wwdc2020-10097",
"staticContentId": 3528,
"eventContentId": 10097,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10097",
"description": "Learn about new features of UICollectionView that make it easier to use and unlock powerful new functionality. We'll show you how to use section snapshots with your diffable data source to create outlines that can expand and collapse, and introduce you to building lists with compositional layout to create UITableView-like interfaces with a collection view. And discover modern techniques for dequeuing cells and configuring their content and styling.\r\n\r\nTo get the most out of this session, you should have a basic understanding of compositional layouts. Watch “Advances in Collection View Layout” from WWDC19 for more information.",
"title": "Advances in UICollectionView",
"originalPublishingDate": "2020-06-23T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS"
],
"keywords": [
"cell",
"collection",
"layout",
"table",
"tableview",
"uicollectionview",
"uitableview"
],
"topicIds": [
22
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "UICollectionViewCompositionalLayout Lists",
"startTimeSeconds": 375,
"endTimeSeconds": 389,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e configuration = u003cspan class=\"syntax-type\"u003eUICollectionLayoutListConfigurationu003c/spanu003e(appearance: .insetGrouped)\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e layout = u003cspan class=\"syntax-type\"u003eUICollectionViewCompositionalLayoutu003c/spanu003e.list(using: configuration)"
},
{
"title": "Cell Registration",
"startTimeSeconds": 453,
"endTimeSeconds": 485,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Example of using new iOS 14 cell registrationu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e reg = u003cspan class=\"syntax-type\"u003eUICollectionViewu003c/spanu003e.u003cspan class=\"syntax-type\"u003eCellRegistrationu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eMyCellu003c/spanu003e, u003cspan class=\"syntax-type\"u003eViewModelu003c/spanu003eu0026gt; { cell, indexPath, model u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// configure cell content u003c/spanu003e\n}\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e dataSource = u003cspan class=\"syntax-type\"u003eUICollectionViewDiffableDataSourceu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eSu003c/spanu003e,u003cspan class=\"syntax-type\"u003eIu003c/spanu003eu0026gt;(collectionView: collectionView) {\n collectionView, indexPath, item -u0026gt; u003cspan class=\"syntax-type\"u003eUICollectionViewCellu003c/spanu003e u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e collectionView.dequeueConfiguredReusableCell(using: reg, u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: indexPath, item: item)\n}"
},
{
"title": ".cell Content Configuration",
"startTimeSeconds": 512,
"endTimeSeconds": 517,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e contentConfiguration = u003cspan class=\"syntax-type\"u003eUIListContentConfigurationu003c/spanu003e.cell()\ncontentConfiguration.image = u003cspan class=\"syntax-type\"u003eUIImageu003c/spanu003e(systemName:u003cspan class=\"syntax-string\"u003e\"hammer\"u003c/spanu003e)\ncontentConfiguration.text = u003cspan class=\"syntax-string\"u003e\"Ready. Set. Code\"u003c/spanu003e\ncell.contentConfiguration = contentConfiguration"
},
{
"title": ".valueCell Content Configuration",
"startTimeSeconds": 518,
"endTimeSeconds": 522,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e contentConfiguration = u003cspan class=\"syntax-type\"u003eUIListContentConfigurationu003c/spanu003e.valueCell()\ncontentConfiguration.image = u003cspan class=\"syntax-type\"u003eUIImageu003c/spanu003e(systemName:u003cspan class=\"syntax-string\"u003e\"hammer\"u003c/spanu003e)\ncontentConfiguration.text = u003cspan class=\"syntax-string\"u003e\"Ready. Set. Code.\"u003c/spanu003e\ncontentConfiguration.secondaryText = u003cspan class=\"syntax-string\"u003e\"#WWDC20\"u003c/spanu003e\ncell.contentConfiguration = contentConfiguration"
},
{
"title": ".subtitleCell Content Configuration",
"startTimeSeconds": 524,
"endTimeSeconds": 531,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e contentConfiguration = u003cspan class=\"syntax-type\"u003eUIListContentConfigurationu003c/spanu003e.subtitleCell()\ncontentConfiguration.image = u003cspan class=\"syntax-type\"u003eUIImageu003c/spanu003e(systemName:u003cspan class=\"syntax-string\"u003e\"hammer\"u003c/spanu003e)\ncontentConfiguration.text = u003cspan class=\"syntax-string\"u003e\"Ready. Set. Code.\"u003c/spanu003e\ncontentConfiguration.secondaryText = u003cspan class=\"syntax-string\"u003e\"#WWDC20\"u003c/spanu003e\ncell.contentConfiguration = contentConfiguration"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10097/3/CE693EFF-2BF8-4B42-B483-04F69015A601/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10097/3/CE693EFF-2BF8-4B42-B483-04F69015A601/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10097/3/CE693EFF-2BF8-4B42-B483-04F69015A601/transcripts/wwdc2020-10097-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10097/3/CE693EFF-2BF8-4B42-B483-04F69015A601/wwdc2020_10097_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10097/3/CE693EFF-2BF8-4B42-B483-04F69015A601/wwdc2020_10097_sd.mp4",
"duration": 595
},
"related": {
"activities": [
"wwdc2020-10026",
"wwdc2020-10027",
"wwdc2020-10105",
"wwdc2020-10907",
"wwdc2019-215",
"wwdc2019-220"
],
"resources": [
1125,
1124,
530
]
}
},
{
"id": "wwdc2020-10017",
"staticContentId": 3579,
"eventContentId": 10017,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10017",
"description": "Core Data is the central way to durably and persistently store information from your app — and we’re going to show you how to refine that implementation for even faster data ingest and fetching. Discover how you can improve data capture with batch insert, tailor fetch requests to your data needs, and react to notifications about changes in the persistent store.\r\n\r\nTo get the most out of this session, you should know and have interacted with Core Data in the past. For more information on the framework, watch “Making Apps with Core Data.”",
"title": "Core Data: Sundries and maxims",
"originalPublishingDate": "2020-06-26T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS"
],
"keywords": [
"batch delete",
"batch ingestion",
"batch insert",
"batch insert with dictionary block",
"batch operations",
"block ingestion",
"dictionary block",
"fetch request",
"history request",
"nsbatchdeleterequest",
"nsbatchinsertrequest",
"nsmanagedobjectcontext",
"persistent history",
"persistent store",
"remote change notification",
"remote change notifications",
"upsert"
],
"topicIds": [
37,
22
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Batch Operations - Enable Persistent History",
"startTimeSeconds": 108,
"endTimeSeconds": 117,
"language": "swift",
"code": "storeDesc.setOption(u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e u003cspan class=\"syntax-type\"u003eNSNumberu003c/spanu003e, forKey: u003cspan class=\"syntax-type\"u003eNSPersistentHistoryTrackingKeyu003c/spanu003e)"
},
{
"title": "NSBatchInsertRequest.h",
"startTimeSeconds": 152,
"endTimeSeconds": 172,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e//NSBatchInsertRequest.hu003c/spanu003e\n\nu003cspan class=\"syntax-meta\"u003e@availableu003c/spanu003e(iOS u003cspan class=\"syntax-number\"u003e13.0u003c/spanu003e, *)\nu003cspan class=\"syntax-keyword\"u003eopenu003c/spanu003e u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eNSBatchInsertRequestu003c/spanu003e : u003cspan class=\"syntax-title\"u003eNSPersistentStoreRequestu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003eopenu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e resultType: u003cspan class=\"syntax-type\"u003eNSBatchInsertRequestResultTypeu003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003econvenienceu003c/spanu003e u003cspan class=\"syntax-keyword\"u003einitu003c/spanu003e(entityName: u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e, objects dictionaries: [[u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e : u003cspan class=\"syntax-type\"u003eAnyu003c/spanu003e]])\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003econvenienceu003c/spanu003e u003cspan class=\"syntax-keyword\"u003einitu003c/spanu003e(entity: u003cspan class=\"syntax-type\"u003eNSEntityDescriptionu003c/spanu003e, objects dictionaries: [[u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e : u003cspan class=\"syntax-type\"u003eAnyu003c/spanu003e]])\n\n u003cspan class=\"syntax-meta\"u003e@availableu003c/spanu003e(iOS u003cspan class=\"syntax-number\"u003e14.0u003c/spanu003e, *)\n u003cspan class=\"syntax-keyword\"u003eopenu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e dictionaryHandler: ((u003cspan class=\"syntax-keyword\"u003einoutu003c/spanu003e u003cspan class=\"syntax-type\"u003eDictionaryu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e, u003cspan class=\"syntax-type\"u003eAnyu003c/spanu003eu0026gt;) -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e)?\n u003cspan class=\"syntax-keyword\"u003eopenu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e managedObjectHandler: ((u003cspan class=\"syntax-keyword\"u003einoutu003c/spanu003e u003cspan class=\"syntax-type\"u003eNSManagedObjectu003c/spanu003e) -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e)?\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003econvenienceu003c/spanu003e u003cspan class=\"syntax-keyword\"u003einitu003c/spanu003e(entity: u003cspan class=\"syntax-type\"u003eNSEntityDescriptionu003c/spanu003e, dictionaryHandler handler: @escaping (u003cspan class=\"syntax-keyword\"u003einoutu003c/spanu003e u003cspan class=\"syntax-type\"u003eDictionaryu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e, u003cspan class=\"syntax-type\"u003eAnyu003c/spanu003eu0026gt;) -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e)\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003econvenienceu003c/spanu003e u003cspan class=\"syntax-keyword\"u003einitu003c/spanu003e(entity: u003cspan class=\"syntax-type\"u003eNSEntityDescriptionu003c/spanu003e, managedObjectHandler handler: @escaping (u003cspan class=\"syntax-keyword\"u003einoutu003c/spanu003e u003cspan class=\"syntax-type\"u003eNSManagedObjectu003c/spanu003e) -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e)\n}"
},
{
"title": "Earthquakes Sample - Regular Save",
"startTimeSeconds": 181,
"endTimeSeconds": 192,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e//Earthquakes Sample - Regular Saveu003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e quakeData u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e quakesBatch {\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e quake = u003cspan class=\"syntax-type\"u003eNSEntityDescriptionu003c/spanu003e.insertNewObject(forEntityName: u003cspan class=\"syntax-string\"u003e\"Quake\"u003c/spanu003e, into: taskContext) u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e? u003cspan class=\"syntax-type\"u003eQuakeu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e { ... }\n u003cspan class=\"syntax-keyword\"u003edou003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e quake.update(with: quakeData)\n } u003cspan class=\"syntax-keyword\"u003ecatchu003c/spanu003e u003cspan class=\"syntax-type\"u003eQuakeErroru003c/spanu003e.missingData {\n ...\n taskContext.delete(quake)\n }\n ...\n }\n u003cspan class=\"syntax-keyword\"u003edou003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e taskContext.save()\n } u003cspan class=\"syntax-keyword\"u003ecatchu003c/spanu003e { ... }"
},
{
"title": "Earthquakes Sample - Batch Insert with Array of Dictionaries",
"startTimeSeconds": 196,
"endTimeSeconds": 204,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e//Earthquakes Sample - Batch Insertu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e quakePropertiesArray = [[u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e:u003cspan class=\"syntax-type\"u003eAnyu003c/spanu003e]]()\nu003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e quake u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e quakesBatch {\n quakePropertiesArray.append(quake.dictionary)\n}\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e batchInsert = u003cspan class=\"syntax-type\"u003eNSBatchInsertRequestu003c/spanu003e(entityName: u003cspan class=\"syntax-string\"u003e\"Quake\"u003c/spanu003e, objects: quakePropertiesArray)\n\nu003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e insertResult : u003cspan class=\"syntax-type\"u003eNSBatchInsertResultu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003edou003c/spanu003e {\n insertResult = u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e taskContext.execute(batchInsert) u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e! u003cspan class=\"syntax-type\"u003eNSBatchInsertResultu003c/spanu003e\n ... \n}"
},
{
"title": "Earthquakes Sample - Batch Insert with a block",
"startTimeSeconds": 208,
"endTimeSeconds": 219,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e//Earthquakes Sample - Batch Insert with a blocku003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e batchInsert = u003cspan class=\"syntax-type\"u003eNSBatchInsertRequestu003c/spanu003e(entityName: u003cspan class=\"syntax-string\"u003e\"Quake\"u003c/spanu003e, dictionaryHandler: { \n (dictionary) u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e (blockCount == batchSize) {\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e\n } u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n dictionary = quakesBatch[blockCount]\n blockCount += u003cspan class=\"syntax-number\"u003e1u003c/spanu003e\n }\n })\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e insertResult : u003cspan class=\"syntax-type\"u003eNSBatchInsertResultu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003edou003c/spanu003e {\n insertResult = u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e taskContext.execute(batchInsert) u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e! u003cspan class=\"syntax-type\"u003eNSBatchInsertResultu003c/spanu003e\n ...\n }"
},
{
"title": "NSBatchInsertRequest - UPSERT",
"startTimeSeconds": 342,
"endTimeSeconds": 369,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e moc = u003cspan class=\"syntax-type\"u003eNSManagedObjectContextu003c/spanu003e(concurrencyType:\n u003cspan class=\"syntax-type\"u003eNSManagedObjectContextConcurrencyTypeu003c/spanu003e.privateQueueConcurrencyType)\n \nmoc.mergePolicy = u003cspan class=\"syntax-type\"u003eNSMergeByPropertyObjectTrumpMergePolicyu003c/spanu003e\n\ninsertResult = u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e moc.execute(insertRequest)"
},
{
"title": "Batch Update Example",
"startTimeSeconds": 390,
"endTimeSeconds": 423,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e//Earthquakes Sample - Batch Updateu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e updateRequest = u003cspan class=\"syntax-type\"u003eNSBatchUpdateRequestu003c/spanu003e(entityName: u003cspan class=\"syntax-string\"u003e\"Quake\"u003c/spanu003e)\nupdateRequest.propertiesToUpdate = [u003cspan class=\"syntax-string\"u003e\"validated\"u003c/spanu003e : u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e]\nupdateRequest.predicate = u003cspan class=\"syntax-type\"u003eNSPredicateu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"%K u0026gt; 2.5\"u003c/spanu003e, u003cspan class=\"syntax-string\"u003e\"magnitude\"u003c/spanu003e)\n\nu003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e updateResult : u003cspan class=\"syntax-type\"u003eNSBatchUpdateResultu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003edou003c/spanu003e {\n updateResult = u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e taskContext.execute(updateRequest) u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e! u003cspan class=\"syntax-type\"u003eNSBatchUpdateResultu003c/spanu003e\n ... \n}"
},
{
"title": "Batch Delete without and with a Fetch Limit",
"startTimeSeconds": 453,
"endTimeSeconds": 500,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Batch Delete without and with a Fetch Limitu003c/spanu003e\n\n u003cspan class=\"syntax-type\"u003eDispatchQueueu003c/spanu003e.global(qos: .background).async {\n moc.performAndWait { () -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003edou003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e expirationDate = u003cspan class=\"syntax-type\"u003eDateu003c/spanu003e.u003cspan class=\"syntax-keyword\"u003einitu003c/spanu003e().addingTimeInterval(-u003cspan class=\"syntax-number\"u003e30u003c/spanu003e*u003cspan class=\"syntax-number\"u003e24u003c/spanu003e*u003cspan class=\"syntax-number\"u003e3600u003c/spanu003e)\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e request = u003cspan class=\"syntax-type\"u003eNSFetchRequestu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eQuakeu003c/spanu003eu0026gt;(entityName: u003cspan class=\"syntax-string\"u003e\"Quake\"u003c/spanu003e)\n request.predicate = u003cspan class=\"syntax-type\"u003eNSPredicateu003c/spanu003e(format:u003cspan class=\"syntax-string\"u003e\"creationDate u0026lt; %@\"u003c/spanu003e, expirationDate)\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e batchDelete = u003cspan class=\"syntax-type\"u003eNSBatchDeleteRequestu003c/spanu003e(fetchRequest: request)\n batchDelete.fetchLimit = u003cspan class=\"syntax-number\"u003e1000u003c/spanu003e\n moc.execute(batchDelete)\n }\n }\n }"
},
{
"title": "Fetch average magnitude of each place",
"startTimeSeconds": 738,
"endTimeSeconds": 764,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e//Fetch average magnitude of each placeu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e magnitudeExp = u003cspan class=\"syntax-type\"u003eNSExpressionu003c/spanu003e(forKeyPath: u003cspan class=\"syntax-string\"u003e\"magnitude\"u003c/spanu003e)\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e avgExp = u003cspan class=\"syntax-type\"u003eNSExpressionu003c/spanu003e(forFunction: u003cspan class=\"syntax-string\"u003e\"avg:\"u003c/spanu003e, arguments: [magnitudeExp])\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e avgDesc = u003cspan class=\"syntax-type\"u003eNSExpressionDescriptionu003c/spanu003e()\navgDesc.expression = avgExp\navgDesc.name = u003cspan class=\"syntax-string\"u003e\"average magnitude\"u003c/spanu003e\navgDesc.expressionResultType = .floatAttributeType\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e fetch = u003cspan class=\"syntax-type\"u003eNSFetchRequestu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eNSFetchRequestResultu003c/spanu003eu0026gt;(entityName: u003cspan class=\"syntax-string\"u003e\"Quake\"u003c/spanu003e)\nfetch.propertiesToFetch = [avgDesc, u003cspan class=\"syntax-string\"u003e\"place\"u003c/spanu003e]\nfetch.propertiesToGroupBy = [u003cspan class=\"syntax-string\"u003e\"place\"u003c/spanu003e]\nfetch.resultType = .dictionaryResultType"
},
{
"title": "NSManagedObjectContext.h - Modernized Notifications",
"startTimeSeconds": 816,
"endTimeSeconds": 831,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e//NSManagedObjectContext.hu003c/spanu003e\n\nu003cspan class=\"syntax-meta\"u003e@availableu003c/spanu003e(iOS u003cspan class=\"syntax-number\"u003e14.0u003c/spanu003e, *)\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eextensionu003c/spanu003e u003cspan class=\"syntax-title\"u003eNSManagedObjectContextu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003estaticu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e willSaveObjectsNotification: u003cspan class=\"syntax-type\"u003eNotificationu003c/spanu003e.u003cspan class=\"syntax-type\"u003eNameu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003estaticu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e didSaveObjectsNotification: u003cspan class=\"syntax-type\"u003eNotificationu003c/spanu003e.u003cspan class=\"syntax-type\"u003eNameu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003estaticu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e didChangeObjectsNotification: u003cspan class=\"syntax-type\"u003eNotificationu003c/spanu003e.u003cspan class=\"syntax-type\"u003eNameu003c/spanu003e\n \n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003estaticu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e didSaveObjectIDsNotification: u003cspan class=\"syntax-type\"u003eNotificationu003c/spanu003e.u003cspan class=\"syntax-type\"u003eNameu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003estaticu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e didMergeChangesObjectIDsNotification: u003cspan class=\"syntax-type\"u003eNotificationu003c/spanu003e.u003cspan class=\"syntax-type\"u003eNameu003c/spanu003e\n}"
},
{
"title": "NSManagedObjectContext.h - Modernized Keys",
"startTimeSeconds": 834,
"endTimeSeconds": 845,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e//NSManagedObjectContext.hu003c/spanu003e\n\nu003cspan class=\"syntax-meta\"u003e@availableu003c/spanu003e(iOS u003cspan class=\"syntax-number\"u003e14.0u003c/spanu003e, *)\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eextensionu003c/spanu003e u003cspan class=\"syntax-title\"u003eNSManagedObjectContextu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eenumu003c/spanu003e u003cspan class=\"syntax-title\"u003eNotificationKeyu003c/spanu003e : u003cspan class=\"syntax-title\"u003eStringu003c/spanu003e u003c/spanu003e{ \n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e sourceContext\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e queryGeneration\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e invalidatedAllObjects\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e insertedObjects\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e updatedObjects\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e deletedObjects\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e refreshedObjects\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e invalidatedObjects\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e insertedObjectIDs\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e updatedObjectIDs\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e deletedObjectIDs\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e refreshedObjectIDs\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e invalidatedObjectIDs\n }\n}"
},
{
"title": "Enable Remote Change Notifications with Persistent History",
"startTimeSeconds": 848,
"endTimeSeconds": 877,
"language": "swift",
"code": "storeDesc.setOption(u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e u003cspan class=\"syntax-type\"u003eNSNumberu003c/spanu003e, forKey: u003cspan class=\"syntax-type\"u003eNSPersistentStoreRemoteChangeNotificationPostOptionKeyu003c/spanu003e)\nstoreDesc.setOption(u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e u003cspan class=\"syntax-type\"u003eNSNumberu003c/spanu003e, forKey: u003cspan class=\"syntax-type\"u003eNSPersistentHistoryTrackingKeyu003c/spanu003e)"
},
{
"title": "History Pointers",
"startTimeSeconds": 979,
"endTimeSeconds": 1025,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e changeDesc = u003cspan class=\"syntax-type\"u003eNSPersistentHistoryChangeu003c/spanu003e.entityDescription(with: moc)\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e request = u003cspan class=\"syntax-type\"u003eNSFetchRequestu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eNSFetchRequestResultu003c/spanu003eu0026gt;()\n\nu003cspan class=\"syntax-comment\"u003e//Set fetch request entity and predicateu003c/spanu003e\nrequest.entity = changeDesc\nrequest.predicate = \n u003cspan class=\"syntax-type\"u003eNSPredicateu003c/spanu003e(format: u003cspan class=\"syntax-string\"u003e\"%K = %@\"u003c/spanu003e,changeDesc?.attributesByName[u003cspan class=\"syntax-string\"u003e\"changedObjectID\"u003c/spanu003e], objectID)\n \nu003cspan class=\"syntax-comment\"u003e//Set up history request with distantPast and set fetch request u003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e historyReq = u003cspan class=\"syntax-type\"u003eNSPersistentHistoryChangeRequestu003c/spanu003e.fetchHistory(after: u003cspan class=\"syntax-type\"u003eDateu003c/spanu003e.distantPast)\nhistoryReq.fetchRequest = request\n \nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e results = u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e moc.execute(historyReq)"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10017/5/F2FB4653-3146-4087-A264-6EFCE0C197D5/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10017/5/F2FB4653-3146-4087-A264-6EFCE0C197D5/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10017/5/F2FB4653-3146-4087-A264-6EFCE0C197D5/transcripts/wwdc2020-10017-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10017/5/F2FB4653-3146-4087-A264-6EFCE0C197D5/wwdc2020_10017_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10017/5/F2FB4653-3146-4087-A264-6EFCE0C197D5/wwdc2020_10017_sd.mp4",
"duration": 1047
},
"related": {
"activities": [
"wwdc2020-10724",
"wwdc2020-10725",
"wwdc2020-10726",
"wwdc2019-230"
],
"resources": [
1169,
1168,
699
]
}
},
{
"id": "wwdc2020-10663",
"staticContentId": 3405,
"eventContentId": 10663,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10663",
"description": "Explore the latest features and improvements for Safari and WebKit. We’ll walk you through updated web APIs, CSS and media features, JavaScript syntax, and more to help you build great experiences for people when they use your website, home screen web apps, or embedded WebKit views.",
"title": "What's new for web developers",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"watchOS"
],
"keywords": [
"airplay",
"animate",
"app-clip-bundle-id",
"app clips",
"apple-itunes-app",
"apple pay",
"ar quick look",
"aspect ratio",
"async clipboard",
"attribute",
"bigint",
"clipboard",
"constructor",
"copy",
"css",
"css animations",
"css shadow part",
"css transitions",
"custom elements",
"customevent",
"dom",
"dynamic-range",
"element",
"emsg",
"enterkeyhint",
"eventtarget",
"exif",
"ext-x-daterange",
"face id",
"fetch",
"fmp4",
"font-family",
"graphics tab",
"hdr",
"high dynamic range",
"html",
"html banner",
"image-orientation",
"instant back",
"javascript",
"keyframeeffect",
"line-break",
"logical assignment",
"metadata",
"nullish coalescing",
"observe",
"operators",
"optional chaining",
"paste",
"pdf",
"performance",
"picture-in-picture",
"pointer events",
"pseudo-selector",
"public class fields",
"readtext",
"remote playback",
"replaceall",
"resizeobserver",
"safari technology preview",
"security key",
"service workers",
"svg",
"system-ui",
"texttrackcue",
"touch id",
"ui-sans-serif",
"ui-serif",
"usb key",
"web animations",
"web api",
"web assembly",
"web authentication",
"webauthn",
"web component",
"web inspector",
"webp",
"writetext",
"xhr",
"yubikey"
],
"topicIds": [
20
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Web Animations API code example",
"startTimeSeconds": 262,
"endTimeSeconds": 282,
"language": "javascript",
"code": "u003cspan class=\"syntax-comment\"u003e// Web Animations API Code Exampleu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e needle = u003cspan class=\"syntax-built_in\"u003edocumentu003c/spanu003e.getElementById(u003cspan class=\"syntax-string\"u003e\"needle\"u003c/spanu003e);\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e logo = u003cspan class=\"syntax-built_in\"u003edocumentu003c/spanu003e.getElementById(u003cspan class=\"syntax-string\"u003e\"logo\"u003c/spanu003e);\nlogo.addEventListener(u003cspan class=\"syntax-string\"u003e\"click\"u003c/spanu003e, () =u0026gt; {\n needle.animate({\n u003cspan class=\"syntax-attr\"u003etransformu003c/spanu003e: [\n u003cspan class=\"syntax-string\"u003e\"rotateX(35deg) rotateZ(13deg)\"u003c/spanu003e, \n u003cspan class=\"syntax-string\"u003e\"rotateX(35deg) rotateZ(733deg)\"u003c/spanu003e,\n ],\n u003cspan class=\"syntax-attr\"u003eeasingu003c/spanu003e: [u003cspan class=\"syntax-string\"u003e\"ease-out\"u003c/spanu003e],\n }, u003cspan class=\"syntax-number\"u003e800u003c/spanu003e);\n});"
},
{
"title": "Resize observer example",
"startTimeSeconds": 403,
"endTimeSeconds": 431,
"language": "javascript",
"code": "u003cspan class=\"syntax-comment\"u003e// Resize Observer Exampleu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e formatPanelObserver = u003cspan class=\"syntax-keyword\"u003enewu003c/spanu003e ResizeObserver(u003cspan class=\"syntax-function\"u003e(u003cspan class=\"syntax-params\"u003eentriesu003c/spanu003e) =u0026gt;u003c/spanu003e {\n entries.forEach(u003cspan class=\"syntax-function\"u003e(u003cspan class=\"syntax-params\"u003eentryu003c/spanu003e) =u0026gt;u003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e container = entry.target;\n container.classList.toggle(u003cspan class=\"syntax-string\"u003e\"small\"u003c/spanu003e, entry.contentRect.width u0026lt; u003cspan class=\"syntax-number\"u003e175u003c/spanu003e);\n }\n});\n\nformatPanelObserver.observe(u003cspan class=\"syntax-built_in\"u003edocumentu003c/spanu003e.getElementById(u003cspan class=\"syntax-string\"u003e\"format-panel\"u003c/spanu003e));"
},
{
"title": "Async Clipboard API plain text programmatic copy",
"startTimeSeconds": 495,
"endTimeSeconds": 501,
"language": "javascript",
"code": "u003cspan class=\"syntax-comment\"u003e// Programmatic copyu003c/spanu003e\ncopyButtonElement.addEventListener(u003cspan class=\"syntax-string\"u003e\"click\"u003c/spanu003e, (event) =u0026gt; {\n navigator.clipboard.writeText(u003cspan class=\"syntax-string\"u003e\"Plain text to copy.\"u003c/spanu003e).then(u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003e =u0026gt;u003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Successful copyu003c/spanu003e\n }, () =u0026gt; {\n u003cspan class=\"syntax-comment\"u003e// Copy failedu003c/spanu003e\n });\n});"
},
{
"title": "Async Clipboard API plain text examples",
"startTimeSeconds": 502,
"endTimeSeconds": 511,
"language": "javascript",
"code": "u003cspan class=\"syntax-comment\"u003e// Programmatic copyu003c/spanu003e\ncopyButtonElement.addEventListener(u003cspan class=\"syntax-string\"u003e\"click\"u003c/spanu003e, (event) =u0026gt; {\n navigator.clipboard.writeText(u003cspan class=\"syntax-string\"u003e\"Plain text to copy.\"u003c/spanu003e).then(u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003e =u0026gt;u003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Successful copyu003c/spanu003e\n }, () =u0026gt; {\n u003cspan class=\"syntax-comment\"u003e// Copy failedu003c/spanu003e\n });\n});\n\nu003cspan class=\"syntax-comment\"u003e// Programmatic pasteu003c/spanu003e\npasteButtonElement.addEventListener(u003cspan class=\"syntax-string\"u003e\"click\"u003c/spanu003e, (event) =u0026gt; {\n navigator.clipboard.readText().then(u003cspan class=\"syntax-function\"u003e(u003cspan class=\"syntax-params\"u003eclipTextu003c/spanu003e) =u0026gt;u003c/spanu003e {\n u003cspan class=\"syntax-built_in\"u003edocumentu003c/spanu003e.querySelector(u003cspan class=\"syntax-string\"u003e\".editor\"u003c/spanu003e).innerText += clipText);\n });\n});"
},
{
"title": "Web Component example markup",
"startTimeSeconds": 625,
"endTimeSeconds": 635,
"language": "xml",
"code": "u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003etemplateu003c/spanu003e u003cspan class=\"syntax-attr\"u003eidu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"format-button\"u003c/spanu003eu0026gt;u003c/spanu003e\n u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003ebuttonu003c/spanu003e u003cspan class=\"syntax-attr\"u003eclassu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"format\"u003c/spanu003eu0026gt;u003c/spanu003e\n u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003espanu003c/spanu003e u003cspan class=\"syntax-attr\"u003eclassu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"icon\"u003c/spanu003eu0026gt;u003c/spanu003eu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003espanu003c/spanu003eu0026gt;u003c/spanu003e\n u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003espanu003c/spanu003e u003cspan class=\"syntax-attr\"u003eclassu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"label\"u003c/spanu003eu0026gt;u003c/spanu003eu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003espanu003c/spanu003eu0026gt;u003c/spanu003e\n u003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003ebuttonu003c/spanu003eu0026gt;u003c/spanu003e\nu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003etemplateu003c/spanu003eu0026gt;u003c/spanu003e"
},
{
"title": "Registering the Web Component",
"startTimeSeconds": 636,
"endTimeSeconds": 661,
"language": "javascript",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e template = u003cspan class=\"syntax-built_in\"u003edocumentu003c/spanu003e.getElementById(u003cspan class=\"syntax-string\"u003e\"format-button\"u003c/spanu003e);\nu003cspan class=\"syntax-built_in\"u003ewindowu003c/spanu003e.customElements.define(template.id, u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eextendsu003c/spanu003e u003cspan class=\"syntax-title\"u003eHTMLElementu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003econstructoru003c/spanu003e() {\n u003cspan class=\"syntax-keyword\"u003esuperu003c/spanu003e();\n\n u003cspan class=\"syntax-keyword\"u003ethisu003c/spanu003e.attachShadow({u003cspan class=\"syntax-attr\"u003emodeu003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"open\"u003c/spanu003e});\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e newButtonElement = template.content.cloneNode(u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e);\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e parts = newButtonElement.querySelectorAll(u003cspan class=\"syntax-string\"u003e\"span\"u003c/spanu003e);\n parts[u003cspan class=\"syntax-number\"u003e0u003c/spanu003e].textContent = u003cspan class=\"syntax-keyword\"u003ethisu003c/spanu003e.getAttribute(u003cspan class=\"syntax-string\"u003e\"data-icon\"u003c/spanu003e);\n parts[u003cspan class=\"syntax-number\"u003e1u003c/spanu003e].textContent = u003cspan class=\"syntax-keyword\"u003ethisu003c/spanu003e.textContent;\n\n u003cspan class=\"syntax-keyword\"u003ethisu003c/spanu003e.shadowRoot.appendChild(newButtonElement);\n u003cspan class=\"syntax-keyword\"u003ethisu003c/spanu003e.addEventListener(u003cspan class=\"syntax-string\"u003e\"click\"u003c/spanu003e, u003cspan class=\"syntax-keyword\"u003ethisu003c/spanu003e.handleClick.bind(u003cspan class=\"syntax-keyword\"u003ethisu003c/spanu003e));\n }\n});"
},
{
"title": "Web Component custom elements",
"startTimeSeconds": 662,
"endTimeSeconds": 691,
"language": "xml",
"code": "u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003eformat-buttonu003c/spanu003e u003cspan class=\"syntax-attr\"u003eidu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"bold\"u003c/spanu003e u003cspan class=\"syntax-attr\"u003edata-iconu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"B\"u003c/spanu003eu0026gt;u003c/spanu003eBoldu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003eformat-buttonu003c/spanu003eu0026gt;u003c/spanu003e\nu003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003eformat-buttonu003c/spanu003e u003cspan class=\"syntax-attr\"u003eidu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"italic\"u003c/spanu003e u003cspan class=\"syntax-attr\"u003edata-iconu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"I\"u003c/spanu003eu0026gt;u003c/spanu003eItalicu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003eformat-buttonu003c/spanu003eu0026gt;u003c/spanu003e\nu003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003eformat-buttonu003c/spanu003e u003cspan class=\"syntax-attr\"u003eidu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"underline\"u003c/spanu003e u003cspan class=\"syntax-attr\"u003edata-iconu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"U\"u003c/spanu003eu0026gt;u003c/spanu003eUnderlineu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003eformat-buttonu003c/spanu003eu0026gt;u003c/spanu003e\nu003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003eformat-buttonu003c/spanu003e u003cspan class=\"syntax-attr\"u003eidu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"strikethrough\"u003c/spanu003e u003cspan class=\"syntax-attr\"u003edata-iconu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"S\"u003c/spanu003eu0026gt;u003c/spanu003eStrikethroughu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003eformat-buttonu003c/spanu003eu0026gt;u003c/spanu003e\nu003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003eformat-buttonu003c/spanu003e u003cspan class=\"syntax-attr\"u003eidu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"paste\"u003c/spanu003e u003cspan class=\"syntax-attr\"u003edata-iconu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"u003cspan class=\"syntax-symbol\"u003eu0026amp;#x1f4cb;u003c/spanu003e\"u003c/spanu003eu0026gt;u003c/spanu003ePasteu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003eformat-buttonu003c/spanu003eu0026gt;u003c/spanu003e"
},
{
"title": "Original example Web Component template",
"startTimeSeconds": 748,
"endTimeSeconds": 750,
"language": "xml",
"code": "u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003etemplateu003c/spanu003e u003cspan class=\"syntax-attr\"u003eidu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"format-button\"u003c/spanu003eu0026gt;u003c/spanu003e\n u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003ebuttonu003c/spanu003e u003cspan class=\"syntax-attr\"u003eclassu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"format\"u003c/spanu003eu0026gt;u003c/spanu003e\n u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003espanu003c/spanu003e u003cspan class=\"syntax-attr\"u003eclassu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"icon\"u003c/spanu003eu0026gt;u003c/spanu003eu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003espanu003c/spanu003eu0026gt;u003c/spanu003e\n u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003espanu003c/spanu003e u003cspan class=\"syntax-attr\"u003eclassu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"label\"u003c/spanu003eu0026gt;u003c/spanu003eu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003espanu003c/spanu003eu0026gt;u003c/spanu003e\n u003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003ebuttonu003c/spanu003eu0026gt;u003c/spanu003e\nu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003etemplateu003c/spanu003eu0026gt;u003c/spanu003e"
},
{
"title": "Example Web Component template with CSS Shadow Parts",
"startTimeSeconds": 750,
"endTimeSeconds": 757,
"language": "xml",
"code": "u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003etemplateu003c/spanu003e u003cspan class=\"syntax-attr\"u003eidu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"format-button\"u003c/spanu003eu0026gt;u003c/spanu003e\n u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003ebuttonu003c/spanu003e u003cspan class=\"syntax-attr\"u003eclassu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"format\"u003c/spanu003eu0026gt;u003c/spanu003e\n u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003espanu003c/spanu003e u003cspan class=\"syntax-attr\"u003epartu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"icon\"u003c/spanu003e u003cspan class=\"syntax-attr\"u003eclassu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"icon\"u003c/spanu003eu0026gt;u003c/spanu003eu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003espanu003c/spanu003eu0026gt;u003c/spanu003e\n u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003espanu003c/spanu003e u003cspan class=\"syntax-attr\"u003epartu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"label\"u003c/spanu003e u003cspan class=\"syntax-attr\"u003eclassu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"label\"u003c/spanu003eu0026gt;u003c/spanu003eu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003espanu003c/spanu003eu0026gt;u003c/spanu003e\n u003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003ebuttonu003c/spanu003eu0026gt;u003c/spanu003e\nu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003etemplateu003c/spanu003eu0026gt;u003c/spanu003e"
},
{
"title": "CSS Shadow Part styles",
"startTimeSeconds": 758,
"endTimeSeconds": 768,
"language": "swift",
"code": "#bold::part(icon) {\n color: u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e(--formatting-button-icon-color);\n font-weight: bold;\n}\n\n#italic::part(icon) {\n color: u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e(--formatting-button-icon-color);\n font-style: italic;\n}\n\n#underline::part(icon) {\n color: u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e(--formatting-button-icon-color);\n text-decoration: underline;\n}"
},
{
"title": "HTML enterkeyhint attribute",
"startTimeSeconds": 796,
"endTimeSeconds": 806,
"language": "xml",
"code": "u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003edivu003c/spanu003e u003cspan class=\"syntax-attr\"u003eidu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"editor\"u003c/spanu003e u003cspan class=\"syntax-attr\"u003econtenteditableu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"true\"u003c/spanu003e u003cspan class=\"syntax-attr\"u003eenterkeyhintu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"send\"u003c/spanu003eu0026gt;u003c/spanu003eu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003edivu003c/spanu003eu0026gt;u003c/spanu003e"
},
{
"title": "System font families",
"startTimeSeconds": 872,
"endTimeSeconds": 884,
"language": "swift",
"code": "font-family: system-ui;\nfont-family: ui-sans-serif;\nfont-family: ui-serif;\nfont-family: ui-monospace;\nfont-family: ui-rounded;"
},
{
"title": "San Francisco font family",
"startTimeSeconds": 885,
"endTimeSeconds": 892,
"language": "swift",
"code": "body {\n font-family: system-ui;\n font-family: ui-sans-serif;\n}"
},
{
"title": "New York font family",
"startTimeSeconds": 893,
"endTimeSeconds": 897,
"language": "swift",
"code": "body {\n font-family: ui-serif;\n}"
},
{
"title": "SF Mono font family",
"startTimeSeconds": 898,
"endTimeSeconds": 901,
"language": "swift",
"code": "body {\n font-family: ui-monospace;\n}"
},
{
"title": "SF Rounded font family",
"startTimeSeconds": 903,
"endTimeSeconds": 906,
"language": "swift",
"code": "body {\n font-family: ui-rounded;\n}"
},
{
"title": "line-break: anywhere",
"startTimeSeconds": 1003,
"endTimeSeconds": 1018,
"language": "swift",
"code": "code {\n line-u003cspan class=\"syntax-keyword\"u003ebreaku003c/spanu003e: anywhere;\n}"
},
{
"title": "Removing margins from subsequent headings",
"startTimeSeconds": 1045,
"endTimeSeconds": 1075,
"language": "swift",
"code": "h1, h2, h3, h4, h5, h6 {\n margin-top: 3em;\n}\n\nh1 + h2,\nh2 + h3,\nh3 + h4,\nh4 + h5,\nh5 + h6 {\n margin-top: u003cspan class=\"syntax-number\"u003e0u003c/spanu003e;\n}"
},
{
"title": "Removing margins from any subsequent headings",
"startTimeSeconds": 1076,
"endTimeSeconds": 1081,
"language": "swift",
"code": "h1, h2, h3, h4, h5, h6 {\n margin-top: 3em;\n}\n\nh1 + h2, h1 + h3, h1 + h4, h1 + h5, h1 + h6,\nh2 + h3, h2 + h3, h2 + h4, h2 + h5, h2 + h6,\nh3 + h4, h3 + h3, h3 + h4, h3 + h5, h3 + h6,\nh4 + h5, h4 + h3, h4 + h4, h4 + h5, h4 + h6,\nh5 + h6, h5 + h3, h5 + h4, h5 + h5, h5 + h6 {\n margin-top: u003cspan class=\"syntax-number\"u003e0u003c/spanu003e;\n}"
},
{
"title": "Using :is() to remove margins from subsequent headings",
"startTimeSeconds": 1082,
"endTimeSeconds": 1091,
"language": "swift",
"code": "h1, h2, h3, h4, h5, h6 {\n margin-top: 3em;\n}\n\n:u003cspan class=\"syntax-keyword\"u003eisu003c/spanu003e(h1, h2, h3, h4, h5, h6) + :u003cspan class=\"syntax-keyword\"u003eisu003c/spanu003e(h1, h2, h3, h4, h5, h6) {\n margin-top: u003cspan class=\"syntax-number\"u003e0u003c/spanu003e;\n}"
},
{
"title": ":is() specificity prevents the override from working",
"startTimeSeconds": 1111,
"endTimeSeconds": 1145,
"language": "swift",
"code": ":u003cspan class=\"syntax-keyword\"u003eisu003c/spanu003e(.intro, .pullquote, #hero) + p {\n text-transform: uppercase;\n}\n\nh2 + p,\nh3 + p,\nh4 + p,\nh5 + p,\nh6 + p {\n text-transform: u003cspan class=\"syntax-keyword\"u003enoneu003c/spanu003e;\n}"
},
{
"title": "WebP graceful fallback to JPG",
"startTimeSeconds": 1193,
"endTimeSeconds": 1195,
"language": "xml",
"code": "u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003epictureu003c/spanu003eu0026gt;u003c/spanu003e\n u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003esourceu003c/spanu003e u003cspan class=\"syntax-attr\"u003esrcsetu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"example.webp\"u003c/spanu003e u003cspan class=\"syntax-attr\"u003etypeu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"image/webp\"u003c/spanu003eu0026gt;u003c/spanu003e\n u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003eimgu003c/spanu003e u003cspan class=\"syntax-attr\"u003esrcu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"example.jpg\"u003c/spanu003e u003cspan class=\"syntax-attr\"u003ealtu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"Example Image\"u003c/spanu003eu0026gt;u003c/spanu003e\nu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003epictureu003c/spanu003eu0026gt;u003c/spanu003e"
},
{
"title": "WebP graceful fallback to JPG and server-side detection",
"startTimeSeconds": 1194,
"endTimeSeconds": 1206,
"language": "xml",
"code": "u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003epictureu003c/spanu003eu0026gt;u003c/spanu003e\n u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003esourceu003c/spanu003e u003cspan class=\"syntax-attr\"u003esrcsetu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"example.webp\"u003c/spanu003e u003cspan class=\"syntax-attr\"u003etypeu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"image/webp\"u003c/spanu003eu0026gt;u003c/spanu003e\n u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003eimgu003c/spanu003e u003cspan class=\"syntax-attr\"u003esrcu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"example.jpg\"u003c/spanu003e u003cspan class=\"syntax-attr\"u003ealtu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"Example Image\"u003c/spanu003eu0026gt;u003c/spanu003e\nu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003epictureu003c/spanu003eu0026gt;u003c/spanu003e\n\nAccept: image/webp,image/png,image/svg+xml,image/*;…"
},
{
"title": "Image with no size attributes",
"startTimeSeconds": 1277,
"endTimeSeconds": 1279,
"language": "xml",
"code": "u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003eimgu003c/spanu003e u003cspan class=\"syntax-attr\"u003esrcu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"MexicoCity.png\"u003c/spanu003eu0026gt;u003c/spanu003e"
},
{
"title": "Image with size attributes",
"startTimeSeconds": 1279,
"endTimeSeconds": 1285,
"language": "xml",
"code": "u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003eimgu003c/spanu003e u003cspan class=\"syntax-attr\"u003esrcu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"MexicoCity.png\"u003c/spanu003e u003cspan class=\"syntax-attr\"u003ewidthu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"560\"u003c/spanu003e u003cspan class=\"syntax-attr\"u003eheightu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"747\"u003c/spanu003eu0026gt;u003c/spanu003e"
},
{
"title": "Respect EXIF image orientation default behavior",
"startTimeSeconds": 1309,
"endTimeSeconds": 1332,
"language": "swift",
"code": "image-orientation: from-image;"
},
{
"title": "Override image orientation to use the raw image capture",
"startTimeSeconds": 1333,
"endTimeSeconds": 1344,
"language": "swift",
"code": "image-orientation: u003cspan class=\"syntax-keyword\"u003enoneu003c/spanu003e;"
},
{
"title": "HDR display CSS media query",
"startTimeSeconds": 1357,
"endTimeSeconds": 1362,
"language": "xml",
"code": "u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003estyleu003c/spanu003eu0026gt;u003c/spanu003eu003cspan class=\"css\"u003e\nu003cspan class=\"syntax-keyword\"u003e@mediau003c/spanu003e u003cspan class=\"syntax-keyword\"u003eonlyu003c/spanu003e screen (u003cspan class=\"syntax-attribute\"u003edynamic-range:u003c/spanu003e high) {\n u003cspan class=\"syntax-comment\"u003e/* HDR-only CSS rules */u003c/spanu003e\n}\nu003c/spanu003eu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003estyleu003c/spanu003eu0026gt;u003c/spanu003e"
},
{
"title": "HDR display CSS media query and JavaScript matchMedia detection",
"startTimeSeconds": 1362,
"endTimeSeconds": 1377,
"language": "xml",
"code": "u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003estyleu003c/spanu003eu0026gt;u003c/spanu003eu003cspan class=\"css\"u003e\nu003cspan class=\"syntax-keyword\"u003e@mediau003c/spanu003e u003cspan class=\"syntax-keyword\"u003eonlyu003c/spanu003e screen (u003cspan class=\"syntax-attribute\"u003edynamic-range:u003c/spanu003e high) {\n u003cspan class=\"syntax-comment\"u003e/* HDR-only CSS rules */u003c/spanu003e\n}\nu003c/spanu003eu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003estyleu003c/spanu003eu0026gt;u003c/spanu003e\n\nu003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003escriptu003c/spanu003eu0026gt;u003c/spanu003eu003cspan class=\"javascript\"u003e\nu003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e (u003cspan class=\"syntax-built_in\"u003ewindowu003c/spanu003e.matchMedia(u003cspan class=\"syntax-string\"u003e\"dynamic-range: high\"u003c/spanu003e)) {\n u003cspan class=\"syntax-comment\"u003e// HDR-specific JavaScriptu003c/spanu003e\n}\nu003c/spanu003eu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003escriptu003c/spanu003eu0026gt;u003c/spanu003e"
},
{
"title": "Remote Playback API example",
"startTimeSeconds": 1399,
"endTimeSeconds": 1414,
"language": "xml",
"code": "u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003evideou003c/spanu003e u003cspan class=\"syntax-attr\"u003eidu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"videoElement\"u003c/spanu003e u003cspan class=\"syntax-attr\"u003esrcu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"https://site.example/video.mp4\"u003c/spanu003eu0026gt;u003c/spanu003eu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003evideou003c/spanu003eu0026gt;u003c/spanu003e\nu003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003ebuttonu003c/spanu003e u003cspan class=\"syntax-attr\"u003eidu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"deviceButton\"u003c/spanu003eu0026gt;u003c/spanu003eSend video to a remote deviceu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003ebuttonu003c/spanu003eu0026gt;u003c/spanu003e\n\nu003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003escriptu003c/spanu003eu0026gt;u003c/spanu003eu003cspan class=\"javascript\"u003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e videoElement = u003cspan class=\"syntax-built_in\"u003edocumentu003c/spanu003e.getElementById(u003cspan class=\"syntax-string\"u003e\"videoElement\"u003c/spanu003e);\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e deviceButton = u003cspan class=\"syntax-built_in\"u003edocumentu003c/spanu003e.getElementById(u003cspan class=\"syntax-string\"u003e\"deviceButton\"u003c/spanu003e);\n deviceButton.addEventListener(u003cspan class=\"syntax-string\"u003e\"click\"u003c/spanu003e, (event) =u0026gt; {\n videoElement.remote.prompt().then(updateRemotePlaybackState);\n });\nu003c/spanu003eu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003escriptu003c/spanu003eu0026gt;u003c/spanu003e"
},
{
"title": "Picture in Picture example",
"startTimeSeconds": 1460,
"endTimeSeconds": 1472,
"language": "xml",
"code": "u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003evideou003c/spanu003e u003cspan class=\"syntax-attr\"u003eidu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"videoElement\"u003c/spanu003e u003cspan class=\"syntax-attr\"u003esrcu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"https://site.example/video.mp4\"u003c/spanu003eu0026gt;u003c/spanu003eu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003evideou003c/spanu003eu0026gt;u003c/spanu003e\nu003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003ebuttonu003c/spanu003e u003cspan class=\"syntax-attr\"u003eidu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"pipButton\"u003c/spanu003eu0026gt;u003c/spanu003eEnter picture-in-picture modeu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003ebuttonu003c/spanu003eu0026gt;u003c/spanu003e\n\nu003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003escriptu003c/spanu003eu0026gt;u003c/spanu003eu003cspan class=\"javascript\"u003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e videoElement = u003cspan class=\"syntax-built_in\"u003edocumentu003c/spanu003e.getElementById(u003cspan class=\"syntax-string\"u003e\"videoElement\"u003c/spanu003e);\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e pipButton = u003cspan class=\"syntax-built_in\"u003edocumentu003c/spanu003e.getElementById(u003cspan class=\"syntax-string\"u003e\"pipButton\"u003c/spanu003e);\n pipButton.addEventListener(u003cspan class=\"syntax-string\"u003e\"click\"u003c/spanu003e, (event) =u0026gt; {\n videoElement.requestPictureInPicture().then(handlePictureInPicture);\n });\nu003c/spanu003eu003cspan class=\"syntax-tag\"u003eu0026lt;/u003cspan class=\"syntax-name\"u003escriptu003c/spanu003eu0026gt;u003c/spanu003e"
},
{
"title": "Nullish coalescing operator",
"startTimeSeconds": 1682,
"endTimeSeconds": 1736,
"language": "javascript",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003ePersonu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003econstructoru003c/spanu003e(firstName, lastName, age) {\n u003cspan class=\"syntax-keyword\"u003ethisu003c/spanu003e.firstName = firstName ?? u003cspan class=\"syntax-string\"u003e\"Unknown\"u003c/spanu003e;\n u003cspan class=\"syntax-keyword\"u003ethisu003c/spanu003e.lastName = lastName ?? u003cspan class=\"syntax-string\"u003e\"Unknown\"u003c/spanu003e;\n u003cspan class=\"syntax-keyword\"u003ethisu003c/spanu003e.age = age ?? u003cspan class=\"syntax-literal\"u003eNaNu003c/spanu003e;\n }\n}\n\nu003cspan class=\"syntax-built_in\"u003econsoleu003c/spanu003e.log(u003cspan class=\"syntax-keyword\"u003enewu003c/spanu003e Person()); \nu003cspan class=\"syntax-comment\"u003e// { firstName: \"Unknown\", lastName: \"Unknown\", age: NaN }u003c/spanu003e\n\nu003cspan class=\"syntax-built_in\"u003econsoleu003c/spanu003e.log(u003cspan class=\"syntax-keyword\"u003enewu003c/spanu003e Person(u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e, u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e, u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e));\nu003cspan class=\"syntax-comment\"u003e// { firstName: false, lastName: false, age: true }u003c/spanu003e\n\nu003cspan class=\"syntax-built_in\"u003econsoleu003c/spanu003e.log(u003cspan class=\"syntax-keyword\"u003enewu003c/spanu003e Person(u003cspan class=\"syntax-string\"u003e\"John\"u003c/spanu003e, u003cspan class=\"syntax-string\"u003e\"\"u003c/spanu003e, u003cspan class=\"syntax-number\"u003e0u003c/spanu003e)); \nu003cspan class=\"syntax-comment\"u003e// { firstName: \"John\", lastName: \"\", age: 0 }u003c/spanu003e\n\nu003cspan class=\"syntax-built_in\"u003econsoleu003c/spanu003e.log(u003cspan class=\"syntax-keyword\"u003enewu003c/spanu003e Person(u003cspan class=\"syntax-string\"u003e\"John\"u003c/spanu003e, u003cspan class=\"syntax-string\"u003e\"Appleseed\"u003c/spanu003e, u003cspan class=\"syntax-number\"u003e42u003c/spanu003e)); \nu003cspan class=\"syntax-comment\"u003e// { firstName: \"John\", lastName: \"Appleseed\", age: 42 }u003c/spanu003e"
},
{
"title": "JavaScript optional chaining example",
"startTimeSeconds": 1749,
"endTimeSeconds": 1780,
"language": "javascript",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003ePersonu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003econstructoru003c/spanu003e(firstName, lastName, age) {\n u003cspan class=\"syntax-keyword\"u003ethisu003c/spanu003e.firstName = firstName ?? u003cspan class=\"syntax-string\"u003e\"Unknown\"u003c/spanu003e;\n u003cspan class=\"syntax-keyword\"u003ethisu003c/spanu003e.lastName = lastName ?? u003cspan class=\"syntax-string\"u003e\"Unknown\"u003c/spanu003e;\n u003cspan class=\"syntax-keyword\"u003ethisu003c/spanu003e.age = age ?? u003cspan class=\"syntax-literal\"u003eNaNu003c/spanu003e;\n u003cspan class=\"syntax-keyword\"u003ethisu003c/spanu003e.name = { u003cspan class=\"syntax-attr\"u003efirstNameu003c/spanu003e: u003cspan class=\"syntax-keyword\"u003ethisu003c/spanu003e.firstName, u003cspan class=\"syntax-attr\"u003elastNameu003c/spanu003e: u003cspan class=\"syntax-keyword\"u003ethisu003c/spanu003e.lastName };\n }\n}\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efunctionu003c/spanu003e u003cspan class=\"syntax-title\"u003eregisteru003c/spanu003e(u003cspan class=\"syntax-params\"u003epersonu003c/spanu003e) u003c/spanu003e{\n u003cspan class=\"syntax-comment\"u003e// Before optional chainingu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e (person !== u003cspan class=\"syntax-literal\"u003eundefinedu003c/spanu003e u0026amp;u0026amp; person.name !== u003cspan class=\"syntax-literal\"u003eundefinedu003c/spanu003e)\n u003cspan class=\"syntax-built_in\"u003econsoleu003c/spanu003e.log(person.name.firstName);\n}\n\nregister(u003cspan class=\"syntax-keyword\"u003enewu003c/spanu003e Person());\nu003cspan class=\"syntax-comment\"u003e// undefinedu003c/spanu003e\n\nregister(u003cspan class=\"syntax-keyword\"u003enewu003c/spanu003e Person(u003cspan class=\"syntax-string\"u003e\"John\"u003c/spanu003e, u003cspan class=\"syntax-string\"u003e\"Appleseed\"u003c/spanu003e));\nu003cspan class=\"syntax-comment\"u003e// \"John\"u003c/spanu003e"
},
{
"title": "JavaScript optional chaining example",
"startTimeSeconds": 1781,
"endTimeSeconds": 1788,
"language": "javascript",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003ePersonu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003econstructoru003c/spanu003e(firstName, lastName, age) {\n u003cspan class=\"syntax-keyword\"u003ethisu003c/spanu003e.firstName = firstName ?? u003cspan class=\"syntax-string\"u003e\"Unknown\"u003c/spanu003e;\n u003cspan class=\"syntax-keyword\"u003ethisu003c/spanu003e.lastName = lastName ?? u003cspan class=\"syntax-string\"u003e\"Unknown\"u003c/spanu003e;\n u003cspan class=\"syntax-keyword\"u003ethisu003c/spanu003e.age = age ?? u003cspan class=\"syntax-literal\"u003eNaNu003c/spanu003e;\n u003cspan class=\"syntax-keyword\"u003ethisu003c/spanu003e.name = { u003cspan class=\"syntax-attr\"u003efirstNameu003c/spanu003e: u003cspan class=\"syntax-keyword\"u003ethisu003c/spanu003e.firstName, u003cspan class=\"syntax-attr\"u003elastNameu003c/spanu003e: u003cspan class=\"syntax-keyword\"u003ethisu003c/spanu003e.lastName };\n }\n}\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efunctionu003c/spanu003e u003cspan class=\"syntax-title\"u003eregisteru003c/spanu003e(u003cspan class=\"syntax-params\"u003epersonu003c/spanu003e) u003c/spanu003e{\n u003cspan class=\"syntax-comment\"u003e// With optional chainingu003c/spanu003e\n u003cspan class=\"syntax-built_in\"u003econsoleu003c/spanu003e.log(person?.name.firstName);\n}\n\nregister(u003cspan class=\"syntax-keyword\"u003enewu003c/spanu003e Person());\n􀆊 u003cspan class=\"syntax-literal\"u003eundefinedu003c/spanu003e\n\nregister(u003cspan class=\"syntax-keyword\"u003enewu003c/spanu003e Person(u003cspan class=\"syntax-string\"u003e\"John\"u003c/spanu003e, u003cspan class=\"syntax-string\"u003e\"Appleseed\"u003c/spanu003e));\n􀆊 u003cspan class=\"syntax-string\"u003e\"John\"u003c/spanu003e"
},
{
"title": "JavaScript optional chaining with indexes",
"startTimeSeconds": 1789,
"endTimeSeconds": 1802,
"language": "javascript",
"code": "u003cspan class=\"syntax-comment\"u003e// Without optional chainingu003c/spanu003e\nu003cspan class=\"syntax-built_in\"u003econsoleu003c/spanu003e.log(person.children[u003cspan class=\"syntax-number\"u003e0u003c/spanu003e]);\nu003cspan class=\"syntax-comment\"u003e// TypeError: undefined is not an objectu003c/spanu003e\n\nu003cspan class=\"syntax-comment\"u003e// With optional chainingu003c/spanu003e\nu003cspan class=\"syntax-built_in\"u003econsoleu003c/spanu003e.log(person.children?.[u003cspan class=\"syntax-number\"u003e0u003c/spanu003e]);\nu003cspan class=\"syntax-comment\"u003e// undefinedu003c/spanu003e"
},
{
"title": "JavaScript optional chaining with methods",
"startTimeSeconds": 1802,
"endTimeSeconds": 1810,
"language": "javascript",
"code": "u003cspan class=\"syntax-comment\"u003e// Without optional chainingu003c/spanu003e\nu003cspan class=\"syntax-built_in\"u003econsoleu003c/spanu003e.log(person.fullName());\n􀆊 u003cspan class=\"syntax-built_in\"u003eTypeErroru003c/spanu003e: person.fullName is not a u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efunctionu003c/spanu003e.\n\n// u003cspan class=\"syntax-title\"u003eWithu003c/spanu003e u003cspan class=\"syntax-title\"u003eoptionalu003c/spanu003e u003cspan class=\"syntax-title\"u003echainingu003c/spanu003e\nu003cspan class=\"syntax-title\"u003econsoleu003c/spanu003e.u003cspan class=\"syntax-title\"u003elogu003c/spanu003e(u003cspan class=\"syntax-params\"u003eperson.fullName?.(u003c/spanu003e));\n􀆊 u003cspan class=\"syntax-title\"u003eundefinedu003c/spanu003eu003c/spanu003e"
},
{
"title": "Logical assignment operators",
"startTimeSeconds": 1823,
"endTimeSeconds": 1842,
"language": "javascript",
"code": "a u0026amp;u0026amp;= b u003cspan class=\"syntax-comment\"u003e// and assignment operatoru003c/spanu003e\na ||= b u003cspan class=\"syntax-comment\"u003e// or assignment operatoru003c/spanu003e\na ??= b u003cspan class=\"syntax-comment\"u003e// nullish assignment operatoru003c/spanu003e"
},
{
"title": "Nullish coalescing approach",
"startTimeSeconds": 1844,
"endTimeSeconds": 1850,
"language": "javascript",
"code": "u003cspan class=\"syntax-comment\"u003e// Nullish coalescing approachu003c/spanu003e\nelement.innerHTML = element.innerHTML ?? u003cspan class=\"syntax-string\"u003e\"Hello World!\"u003c/spanu003e"
},
{
"title": "Logical assignment operator",
"startTimeSeconds": 1852,
"endTimeSeconds": 1866,
"language": "swift",
"code": "a u0026amp;u0026amp;= b u003cspan class=\"syntax-comment\"u003e// and assignment operatoru003c/spanu003e\na ||= b u003cspan class=\"syntax-comment\"u003e// or assignment operatoru003c/spanu003e\na ??= b u003cspan class=\"syntax-comment\"u003e// nullish assignment operatoru003c/spanu003e\n\nu003cspan class=\"syntax-comment\"u003e// Nullish coalescing approachu003c/spanu003e\nelement.innerHTML = element.innerHTML ?? u003cspan class=\"syntax-string\"u003e\"Hello World!\"u003c/spanu003e\n\nu003cspan class=\"syntax-comment\"u003e// Logical assignment operatoru003c/spanu003e\nelement.innerHTML ??= u003cspan class=\"syntax-string\"u003e\"Hello World!\"u003c/spanu003e"
},
{
"title": "Public class fields",
"startTimeSeconds": 1853,
"endTimeSeconds": 1905,
"language": "javascript",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003ePersonu003c/spanu003e u003c/spanu003e{\n firstName = u003cspan class=\"syntax-string\"u003e\"\"u003c/spanu003e;\n lastName = u003cspan class=\"syntax-string\"u003e\"\"u003c/spanu003e;\n age = u003cspan class=\"syntax-literal\"u003eNaNu003c/spanu003e;\n children = [];\n\n u003cspan class=\"syntax-keyword\"u003econstructoru003c/spanu003e(firstName, lastName, age) {\n u003cspan class=\"syntax-keyword\"u003ethisu003c/spanu003e.firstName = firstName ?? u003cspan class=\"syntax-string\"u003e\"Unknown\"u003c/spanu003e;\n u003cspan class=\"syntax-keyword\"u003ethisu003c/spanu003e.lastName = lastName ?? u003cspan class=\"syntax-string\"u003e\"Unknown\"u003c/spanu003e;\n u003cspan class=\"syntax-keyword\"u003ethisu003c/spanu003e.age = age ?? u003cspan class=\"syntax-literal\"u003eNaNu003c/spanu003e;\n }\n}"
},
{
"title": "App Clips banner",
"startTimeSeconds": 2033,
"endTimeSeconds": 2050,
"language": "xml",
"code": "u003cspan class=\"syntax-tag\"u003eu0026lt;u003cspan class=\"syntax-name\"u003emetau003c/spanu003e u003cspan class=\"syntax-attr\"u003enameu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"apple-itunes-app\"u003c/spanu003e\n u003cspan class=\"syntax-attr\"u003econtentu003c/spanu003e=u003cspan class=\"syntax-string\"u003e\"app-id=myAppStoreID,\n app-clip-bundle-id=clipBundleID,\n affiliate-data=myAffiliateData,\n app-argument=myURL\"u003c/spanu003eu0026gt;u003c/spanu003e"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10663/5/07AE41F3-7DC1-47F7-BD89-EF68948C4935/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10663/5/07AE41F3-7DC1-47F7-BD89-EF68948C4935/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10663/4/CD370943-444D-4A23-8D1E-C2F93151F7DF/transcripts/wwdc2020-10663-transcripts.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10663/5/07AE41F3-7DC1-47F7-BD89-EF68948C4935/wwdc2020_10663_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10663/5/07AE41F3-7DC1-47F7-BD89-EF68948C4935/wwdc2020_10663_sd.mp4",
"duration": 2165
},
"related": {
"activities": [
"wwdc2020-10188",
"wwdc2020-10646",
"wwdc2020-10665",
"wwdc2020-10670",
"wwdc2020-10740",
"wwdc2020-10743",
"wwdc2020-10744",
"wwdc2020-10836"
],
"resources": [
989,
988,
774,
773,
772,
771
]
}
},
{
"id": "wwdc2020-10052",
"staticContentId": 3587,
"eventContentId": 10052,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10052",
"description": "Build iPhone and iPad apps with fluid interfaces and easily-accessible contextual information. We’ll show you how to integrate the latest UIKit controls into your app to best take advantage of menus, date pickers, page controls, and segmented controllers. Learn how to adopt Menus throughly your user interface, and explore how UIAction can help unify your event handling.\r\n\r\nOnce you’ve learned about these new controls, watch “Design with iOS pickers, menus and actions” to discover how to design great interfaces with these tools and APIs.",
"title": "Build with iOS pickers, menus and actions",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS"
],
"keywords": [
"uicontrol"
],
"topicIds": [
22
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "UIPageControl example",
"startTimeSeconds": 274,
"endTimeSeconds": 318,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e pageControl = u003cspan class=\"syntax-type\"u003eUIPageControlu003c/spanu003e()\npageControl.numberOfPages = u003cspan class=\"syntax-number\"u003e5u003c/spanu003e\n\npageControl.backgroundStyle = .prominent\n\npageControl.preferredIndicatorImage =\n u003cspan class=\"syntax-type\"u003eUIImageu003c/spanu003e(systemName: u003cspan class=\"syntax-string\"u003e\"bookmark.fill\"u003c/spanu003e)\n\npageControl.setIndicatorImage(\n u003cspan class=\"syntax-type\"u003eUIImageu003c/spanu003e(systemName: u003cspan class=\"syntax-string\"u003e\"heart.fill\"u003c/spanu003e), forPage: u003cspan class=\"syntax-number\"u003e0u003c/spanu003e)"
},
{
"title": "UIColorPickerViewController example",
"startTimeSeconds": 416,
"endTimeSeconds": 451,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e color = u003cspan class=\"syntax-type\"u003eUIColoru003c/spanu003e.blue\nu003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e colorPicker = u003cspan class=\"syntax-type\"u003eUIColorPickerViewControlleru003c/spanu003e()\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003epickColoru003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n colorPicker.supportsAlpha = u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e\n colorPicker.selectedColor = color\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.present(colorPicker,\n animated: u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e,\n completion: u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e)\n}\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ecolorPickerViewControllerDidSelectColoru003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e\n viewController: UIColorPickerViewController)u003c/spanu003eu003c/spanu003e {\n color = viewController.selectedColor\n}\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ecolorPickerViewControllerDidFinishu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e\n viewController: UIColorPickerViewController)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Do nothingu003c/spanu003e\n}"
},
{
"title": "UIDatePicker example",
"startTimeSeconds": 604,
"endTimeSeconds": 642,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e datePicker = u003cspan class=\"syntax-type\"u003eUIDatePickeru003c/spanu003e()\ndatePicker.date = u003cspan class=\"syntax-type\"u003eDateu003c/spanu003e(timeIntervalSinceReferenceDate:\n timeInterval)\n\ndatePicker.preferredDatePickerStyle = .compact\n\ndatePicker.calendar = u003cspan class=\"syntax-type\"u003eCalendaru003c/spanu003e(identifier: .japanese)\ndatePicker.datePickerMode = .date\n\ndatePicker.addTarget(u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e,\n action: #selector(dateSet),\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: .valueChanged)"
},
{
"title": "UIDeferredMenuElement example",
"startTimeSeconds": 860,
"endTimeSeconds": 880,
"language": "swift",
"code": "button.menu = u003cspan class=\"syntax-type\"u003eUIMenuu003c/spanu003e(title: u003cspan class=\"syntax-string\"u003e\"\"u003c/spanu003e, children: [\n u003cspan class=\"syntax-type\"u003eUIMenuu003c/spanu003e(title: u003cspan class=\"syntax-string\"u003e\"\"u003c/spanu003e, options: .displayInline, children: (u003cspan class=\"syntax-number\"u003e1u003c/spanu003e...u003cspan class=\"syntax-number\"u003e2u003c/spanu003e).u003cspan class=\"syntax-built_in\"u003emapu003c/spanu003e { u003cspan class=\"syntax-type\"u003eUIActionu003c/spanu003e(title: u003cspan class=\"syntax-string\"u003e\"Static Item \\($0)\"u003c/spanu003e) { action u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e }}),\n u003cspan class=\"syntax-type\"u003eUIDeferredMenuElementu003c/spanu003e({ completion u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-type\"u003eDispatchQueueu003c/spanu003e.main.asyncAfter(deadline: .now() + u003cspan class=\"syntax-number\"u003e2.0u003c/spanu003e) {\n completion([u003cspan class=\"syntax-type\"u003eUIMenuu003c/spanu003e(title: u003cspan class=\"syntax-string\"u003e\"\"u003c/spanu003e, options: .displayInline, children: (u003cspan class=\"syntax-number\"u003e1u003c/spanu003e...u003cspan class=\"syntax-number\"u003e2u003c/spanu003e).u003cspan class=\"syntax-built_in\"u003emapu003c/spanu003e { u003cspan class=\"syntax-type\"u003eUIActionu003c/spanu003e(title: u003cspan class=\"syntax-string\"u003e\"Dynamic Item \\($0)\"u003c/spanu003e) { action u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e }})])\n }\n }),\n])"
},
{
"title": "updateVisibleMenu example",
"startTimeSeconds": 890,
"endTimeSeconds": 915,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.contextMenuInteraction.updateVisibleMenu { currentMenu -u0026gt; u003cspan class=\"syntax-type\"u003eUIMenuu003c/spanu003e u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n currentMenu.children.forEach { element u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e action = element u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e? u003cspan class=\"syntax-type\"u003eUIActionu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e { u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e }\n \n action.state = u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e.random() ? .off : .on\n action.attributes = u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e.random() ? [.hidden] : []\n }\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e currentMenu\n}"
},
{
"title": "UIBarButtonItem example",
"startTimeSeconds": 965,
"endTimeSeconds": 1025,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e saveAction = u003cspan class=\"syntax-type\"u003eUIActionu003c/spanu003e(title: u003cspan class=\"syntax-string\"u003e\"\"u003c/spanu003e) { action u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e }\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e saveMenu = u003cspan class=\"syntax-type\"u003eUIMenuu003c/spanu003e(title: u003cspan class=\"syntax-string\"u003e\"\"u003c/spanu003e, children: [\n u003cspan class=\"syntax-type\"u003eUIActionu003c/spanu003e(title: u003cspan class=\"syntax-string\"u003e\"Copy\"u003c/spanu003e, image: u003cspan class=\"syntax-type\"u003eUIImageu003c/spanu003e(systemName: u003cspan class=\"syntax-string\"u003e\"doc.on.doc\"u003c/spanu003e)) { action u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e },\n u003cspan class=\"syntax-type\"u003eUIActionu003c/spanu003e(title: u003cspan class=\"syntax-string\"u003e\"Rename\"u003c/spanu003e, image: u003cspan class=\"syntax-type\"u003eUIImageu003c/spanu003e(systemName: u003cspan class=\"syntax-string\"u003e\"pencil\"u003c/spanu003e)) { action u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e },\n u003cspan class=\"syntax-type\"u003eUIActionu003c/spanu003e(title: u003cspan class=\"syntax-string\"u003e\"Duplicate\"u003c/spanu003e, image: u003cspan class=\"syntax-type\"u003eUIImageu003c/spanu003e(systemName: u003cspan class=\"syntax-string\"u003e\"plus.square.on.square\"u003c/spanu003e)) { action u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e },\n u003cspan class=\"syntax-type\"u003eUIActionu003c/spanu003e(title: u003cspan class=\"syntax-string\"u003e\"Move\"u003c/spanu003e, image: u003cspan class=\"syntax-type\"u003eUIImageu003c/spanu003e(systemName: u003cspan class=\"syntax-string\"u003e\"folder\"u003c/spanu003e)) { action u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e },\n])\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e optionsImage = u003cspan class=\"syntax-type\"u003eUIImageu003c/spanu003e(systemName: u003cspan class=\"syntax-string\"u003e\"ellipsis.circle\"u003c/spanu003e)\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e optionsMenu = u003cspan class=\"syntax-type\"u003eUIMenuu003c/spanu003e(title: u003cspan class=\"syntax-string\"u003e\"\"u003c/spanu003e, children: [\n u003cspan class=\"syntax-type\"u003eUIActionu003c/spanu003e(title: u003cspan class=\"syntax-string\"u003e\"Info\"u003c/spanu003e, image: u003cspan class=\"syntax-type\"u003eUIImageu003c/spanu003e(systemName: u003cspan class=\"syntax-string\"u003e\"info.circle\"u003c/spanu003e)) { action u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e },\n u003cspan class=\"syntax-type\"u003eUIActionu003c/spanu003e(title: u003cspan class=\"syntax-string\"u003e\"Share\"u003c/spanu003e, image: u003cspan class=\"syntax-type\"u003eUIImageu003c/spanu003e(systemName: u003cspan class=\"syntax-string\"u003e\"square.and.arrow.up\"u003c/spanu003e)) { action u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e },\n u003cspan class=\"syntax-type\"u003eUIActionu003c/spanu003e(title: u003cspan class=\"syntax-string\"u003e\"Collaborate\"u003c/spanu003e, image: u003cspan class=\"syntax-type\"u003eUIImageu003c/spanu003e(systemName: u003cspan class=\"syntax-string\"u003e\"person.crop.circle.badge.plus\"u003c/spanu003e)) { action u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e },\n])\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e revertAction = u003cspan class=\"syntax-type\"u003eUIActionu003c/spanu003e(title: u003cspan class=\"syntax-string\"u003e\"Revert\"u003c/spanu003e) { action u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e }\nu003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.toolbarItems = [\n u003cspan class=\"syntax-type\"u003eUIBarButtonItemu003c/spanu003e(systemItem: .save, primaryAction: saveAction, menu: saveMenu),\n .fixedSpace(width:u003cspan class=\"syntax-number\"u003e20.0u003c/spanu003e),\n u003cspan class=\"syntax-type\"u003eUIBarButtonItemu003c/spanu003e(image: optionsImage, menu: optionsMenu),\n .flexibleSpace(),\n u003cspan class=\"syntax-type\"u003eUIBarButtonItemu003c/spanu003e(primaryAction: revertAction),\n]"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10052/5/C534955F-BDE1-4CDE-87C3-320B97F2AF8E/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10052/5/C534955F-BDE1-4CDE-87C3-320B97F2AF8E/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10052/5/C534955F-BDE1-4CDE-87C3-320B97F2AF8E/transcripts/wwdc2020-10052-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10052/5/C534955F-BDE1-4CDE-87C3-320B97F2AF8E/wwdc2020_10052_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10052/5/C534955F-BDE1-4CDE-87C3-320B97F2AF8E/wwdc2020_10052_sd.mp4",
"duration": 1221
},
"related": {
"activities": [
"wwdc2020-10056",
"wwdc2020-10093",
"wwdc2020-10107",
"wwdc2020-10205",
"wwdc2020-10652",
"wwdc2020-10906",
"wwdc2020-10908",
"wwdc2020-20007"
],
"resources": [
1175,
1174,
890
]
}
},
{
"id": "wwdc2020-10197",
"staticContentId": 3654,
"eventContentId": 10197,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10197",
"description": "Whether you’re hosting event information in your app, on the web, or in an email, Siri Event Suggestions can help people keep track of their commitments — without compromising their privacy. We’ll show you how to set up your reservations so that they automatically show up in the Calendar app and how to work with the Siri Event Suggestions APIs for iOS and Markup for web and email.",
"title": "Broaden your reach with Siri Event Suggestions",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"watchOS"
],
"keywords": [
"calendar",
"donations",
"email",
"events",
"intents",
"mail",
"safari",
"shortcuts",
"siri event suggestions",
"travel",
"web"
],
"topicIds": [
33,
21,
20,
17
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "JSON-LD",
"startTimeSeconds": 391,
"endTimeSeconds": 402,
"language": "json",
"code": "u0026lt;script type=u003cspan class=\"syntax-string\"u003e\"application/ld+json\"u003c/spanu003eu0026gt;\n{\n  u003cspan class=\"syntax-attr\"u003e\"@context\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"http://schema.org\"u003c/spanu003e,\n  u003cspan class=\"syntax-attr\"u003e\"@type\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"FoodEstablishmentReservation\"u003c/spanu003e,\n  u003cspan class=\"syntax-attr\"u003e\"reservationStatus\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"http://schema.org/ReservationConfirmed\"u003c/spanu003e,\n  u003cspan class=\"syntax-attr\"u003e\"reservationId\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"IWDSCA\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"partySize\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"2\"u003c/spanu003e,\n  u003cspan class=\"syntax-attr\"u003e\"reservationFor\"u003c/spanu003e: {\n    u003cspan class=\"syntax-attr\"u003e\"@type\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"FoodEstablishment\"u003c/spanu003e,\n    u003cspan class=\"syntax-attr\"u003e\"name\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"EPIC Steak\"u003c/spanu003e,\n    u003cspan class=\"syntax-attr\"u003e\"startDate\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"2020-06-26T19:30:00-07:00\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"telephone\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"(415)369-9955\"u003c/spanu003e\n u003cspan class=\"syntax-string\"u003e\"address\"u003c/spanu003e: {\n u003cspan class=\"syntax-attr\"u003e\"@type\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"http://schema.org/PostalAddress\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"streetAddress\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"369 The Embarcadero\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"addressLocality\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"San Francisco\"u003c/spanu003e\n u003cspan class=\"syntax-string\"u003e\"addressRegion\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"CA\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"postalCode\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"95105\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"addressCountry\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"USA\"u003c/spanu003e\n    }\n  }\n}\nu0026lt;/scriptu0026gt;"
},
{
"title": "Microdata",
"startTimeSeconds": 405,
"endTimeSeconds": 419,
"language": "json",
"code": "u0026lt;div itemscope itemtype=u003cspan class=\"syntax-string\"u003e\"FoodEstablishmentReservation\"u003c/spanu003eu0026gt; \n  u0026lt;link itemprop=u003cspan class=\"syntax-string\"u003e\"reservationStatus\"u003c/spanu003e href=u003cspan class=\"syntax-string\"u003e\"http://schema.org/ReservationConfirmed\"u003c/spanu003e/u0026gt;\n  u0026lt;meta itemprop=u003cspan class=\"syntax-string\"u003e\"reservationId\"u003c/spanu003e content=u003cspan class=\"syntax-string\"u003e\"IWDSCA\"u003c/spanu003e/u0026gt;\n  u0026lt;meta itemprop=u003cspan class=\"syntax-string\"u003e\"partySize\"u003c/spanu003e content=u003cspan class=\"syntax-string\"u003e\"2\"u003c/spanu003e/u0026gt;\n  u0026lt;div itemprop=u003cspan class=\"syntax-string\"u003e\"reservationFor\"u003c/spanu003e itemscope itemtype=u003cspan class=\"syntax-string\"u003e\"FoodEstablishment\"u003c/spanu003eu0026gt;\n    u0026lt;meta itemprop=u003cspan class=\"syntax-string\"u003e\"name\"u003c/spanu003e content=u003cspan class=\"syntax-string\"u003e\"EPIC Steak\"u003c/spanu003e/u0026gt;\n    u0026lt;meta itemprop=u003cspan class=\"syntax-string\"u003e\"startDate\"u003c/spanu003e content=u003cspan class=\"syntax-string\"u003e\"2020-06-26T19:30:00-07:00\"u003c/spanu003e/u0026gt;\n    u0026lt;meta itemprop=u003cspan class=\"syntax-string\"u003e\"telephone\"u003c/spanu003e content=u003cspan class=\"syntax-string\"u003e\"(415)369-9955\"u003c/spanu003e/u0026gt;\n    u0026lt;div itemprop=u003cspan class=\"syntax-string\"u003e\"address\"u003c/spanu003e itemscope itemtype=u003cspan class=\"syntax-string\"u003e\"PostalAddress\"u003c/spanu003eu0026gt;\n    u0026lt;meta itemprop=u003cspan class=\"syntax-string\"u003e\"streetAddress\"u003c/spanu003e content=u003cspan class=\"syntax-string\"u003e\"369 The Embarcadero\"u003c/spanu003e/u0026gt;\n      u0026lt;meta itemprop=u003cspan class=\"syntax-string\"u003e\"addressLocality\"u003c/spanu003e content=u003cspan class=\"syntax-string\"u003e\"San Francisco\"u003c/spanu003e/u0026gt;\n      u0026lt;meta itemprop=u003cspan class=\"syntax-string\"u003e\"addressRegion\"u003c/spanu003e content=u003cspan class=\"syntax-string\"u003e\"CA\"u003c/spanu003e/u0026gt;\n      u0026lt;meta itemprop=u003cspan class=\"syntax-string\"u003e\"postalCode\"u003c/spanu003e content=u003cspan class=\"syntax-string\"u003e\"95105\"u003c/spanu003e/u0026gt;\n u0026lt;meta itemprop=u003cspan class=\"syntax-string\"u003e\"addressCountry\"u003c/spanu003e content=u003cspan class=\"syntax-string\"u003e\"USA\"u003c/spanu003e/u0026gt;\n    u0026lt;/divu0026gt;\n  u0026lt;/divu0026gt;\nu0026lt;/divu0026gt;"
},
{
"title": "Modified Reservation JSON-LD",
"startTimeSeconds": 418,
"endTimeSeconds": 436,
"language": "json",
"code": "u0026lt;script type=u003cspan class=\"syntax-string\"u003e\"application/ld+json\"u003c/spanu003eu0026gt;\n{\n  u003cspan class=\"syntax-attr\"u003e\"@context\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"http://schema.org\"u003c/spanu003e,\n  u003cspan class=\"syntax-attr\"u003e\"@type\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"FoodEstablishmentReservation\"u003c/spanu003e,\n  u003cspan class=\"syntax-attr\"u003e\"reservationStatus\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"http://schema.org/ReservationConfirmed\"u003c/spanu003e,\n  u003cspan class=\"syntax-attr\"u003e\"reservationId\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"IWDSCA\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"partySize\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"2\"u003c/spanu003e,\n  u003cspan class=\"syntax-attr\"u003e\"reservationFor\"u003c/spanu003e: {\n    u003cspan class=\"syntax-attr\"u003e\"@type\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"FoodEstablishment\"u003c/spanu003e,\n    u003cspan class=\"syntax-attr\"u003e\"name\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"EPIC Steak\"u003c/spanu003e,\n    u003cspan class=\"syntax-attr\"u003e\"startDate\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"2020-06-26T18:30:00-07:00\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"telephone\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"(415)369-9955\"u003c/spanu003e\n u003cspan class=\"syntax-string\"u003e\"address\"u003c/spanu003e: {\n u003cspan class=\"syntax-attr\"u003e\"@type\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"http://schema.org/PostalAddress\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"streetAddress\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"369 The Embarcadero\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"addressLocality\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"San Francisco\"u003c/spanu003e\n u003cspan class=\"syntax-string\"u003e\"addressRegion\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"CA\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"postalCode\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"95105\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"addressCountry\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"USA\"u003c/spanu003e\n    }\n  }\n}\nu0026lt;/scriptu0026gt;"
},
{
"title": "Cancelled Reservation JSON-LD",
"startTimeSeconds": 441,
"endTimeSeconds": 448,
"language": "json",
"code": "u0026lt;script type=u003cspan class=\"syntax-string\"u003e\"application/ld+json\"u003c/spanu003eu0026gt;\n{\n  u003cspan class=\"syntax-attr\"u003e\"@context\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"http://schema.org\"u003c/spanu003e,\n  u003cspan class=\"syntax-attr\"u003e\"@type\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"FoodEstablishmentReservation\"u003c/spanu003e,\n  u003cspan class=\"syntax-attr\"u003e\"reservationStatus\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"http://schema.org/ReservationCancelled\"u003c/spanu003e,\n  u003cspan class=\"syntax-attr\"u003e\"reservationId\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"IWDSCA\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"partySize\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"2\"u003c/spanu003e,\n  u003cspan class=\"syntax-attr\"u003e\"reservationFor\"u003c/spanu003e: {\n    u003cspan class=\"syntax-attr\"u003e\"@type\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"FoodEstablishment\"u003c/spanu003e,\n    u003cspan class=\"syntax-attr\"u003e\"name\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"EPIC Steak\"u003c/spanu003e,\n    u003cspan class=\"syntax-attr\"u003e\"startDate\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"2020-06-26T19:30:00-07:00\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"telephone\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"(415)369-9955\"u003c/spanu003e\n u003cspan class=\"syntax-string\"u003e\"address\"u003c/spanu003e: {\n u003cspan class=\"syntax-attr\"u003e\"@type\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"http://schema.org/PostalAddress\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"streetAddress\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"369 The Embarcadero\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"addressLocality\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"San Francisco\"u003c/spanu003e\n u003cspan class=\"syntax-string\"u003e\"addressRegion\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"CA\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"postalCode\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"95105\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"addressCountry\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"USA\"u003c/spanu003e\n    }\n  }\n}\nu0026lt;/scriptu0026gt;"
},
{
"title": "SuggestionsAllowAnyDomainForMarkup default",
"startTimeSeconds": 493,
"endTimeSeconds": 497,
"language": "bash",
"code": "defaults write com.apple.suggestions SuggestionsAllowAnyDomainForMarkup -bool u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e"
},
{
"title": "SuggestionsAllowUnverifiedSourceForMarkup default",
"startTimeSeconds": 505,
"endTimeSeconds": 509,
"language": "bash",
"code": "defaults write com.apple.suggestions SuggestionsAllowUnverifiedSourceForMarkup -bool u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e"
},
{
"title": "SuggestionsAllowAnyDomainForMarkup default",
"startTimeSeconds": 529,
"endTimeSeconds": 533,
"language": "bash",
"code": "defaults write com.apple.suggestions SuggestionsAllowAnyDomainForMarkup -bool u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e"
},
{
"title": "SuggestionsAllowUnverifiedSourceForMarkup default",
"startTimeSeconds": 543,
"endTimeSeconds": 547,
"language": "swift",
"code": "defaults write com.apple.suggestions u003cspan class=\"syntax-type\"u003eSuggestionsAllowUnverifiedSourceForMarkupu003c/spanu003e -bool u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e"
},
{
"title": "Reservation Confirmation JSON-LD",
"startTimeSeconds": 632,
"endTimeSeconds": 655,
"language": "json",
"code": "u0026lt;script type='application/ld+json'u0026gt;\n{\n u003cspan class=\"syntax-attr\"u003e\"@context\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"http://schema.org\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"@type\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"http://schema.org/FoodEstablishmentReservation\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"reservationId\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"IWDSCA\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"reservationStatus\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"http://schema.org/ReservationConfirmed\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"url\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"http://localhost:3000/reservations/6\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"underName\"u003c/spanu003e: {\n u003cspan class=\"syntax-attr\"u003e\"@type\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"http://schema.org/Person\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"name\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"John Appleseed\"u003c/spanu003e\n },\n u003cspan class=\"syntax-attr\"u003e\"broker\"u003c/spanu003e: {\n u003cspan class=\"syntax-attr\"u003e\"@type\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"http://schema.org/Organization\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"name\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"Apple Reservations\"u003c/spanu003e\n },\n u003cspan class=\"syntax-attr\"u003e\"startTime\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"2020-06-26T19:30:00-07:00\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"partySize\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"2\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"reservationFor\"u003c/spanu003e: {\n u003cspan class=\"syntax-attr\"u003e\"@type\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"http://schema.org/FoodEstablishment\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"name\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"EPIC Steak\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"telephone\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"(415)369-9955\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"address\"u003c/spanu003e: {\n u003cspan class=\"syntax-attr\"u003e\"@type\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"http://schema.org/PostalAddress\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"streetAddress\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"369 The Embarcadero\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"addressLocality\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"San Francisco\"u003c/spanu003e\n u003cspan class=\"syntax-string\"u003e\"addressRegion\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"CA\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"postalCode\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"95105\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"addressCountry\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"USA\"u003c/spanu003e\n }\n }\n}\nu0026lt;/scriptu0026gt;"
},
{
"title": "Reservation Cancelled JSON-LD",
"startTimeSeconds": 664,
"endTimeSeconds": 671,
"language": "json",
"code": "u0026lt;script type='application/ld+json'u0026gt;\n{\n u003cspan class=\"syntax-attr\"u003e\"@context\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"http://schema.org\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"@type\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"http://schema.org/FoodEstablishmentReservation\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"reservationId\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"IWDSCA\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"reservationStatus\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"http://schema.org/ReservationCancelled\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"url\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"http://localhost:3000/reservations/6\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"underName\"u003c/spanu003e: {\n u003cspan class=\"syntax-attr\"u003e\"@type\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"http://schema.org/Person\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"name\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"John Appleseed\"u003c/spanu003e\n },\n u003cspan class=\"syntax-attr\"u003e\"broker\"u003c/spanu003e: {\n u003cspan class=\"syntax-attr\"u003e\"@type\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"http://schema.org/Organization\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"name\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"Apple Reservations\"u003c/spanu003e\n },\n u003cspan class=\"syntax-attr\"u003e\"startTime\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"2020-06-26T19:30:00-07:00\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"partySize\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"2\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"reservationFor\"u003c/spanu003e: {\n u003cspan class=\"syntax-attr\"u003e\"@type\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"http://schema.org/FoodEstablishment\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"name\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"EPIC Steak\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"telephone\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"(415)369-9955\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"address\"u003c/spanu003e: {\n u003cspan class=\"syntax-attr\"u003e\"@type\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"http://schema.org/PostalAddress\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"streetAddress\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"369 The Embarcadero\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"addressLocality\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"San Francisco\"u003c/spanu003e\n u003cspan class=\"syntax-string\"u003e\"addressRegion\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"CA\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"postalCode\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"95105\"u003c/spanu003e,\n u003cspan class=\"syntax-attr\"u003e\"addressCountry\"u003c/spanu003e: u003cspan class=\"syntax-string\"u003e\"USA\"u003c/spanu003e\n }\n }\n}\nu0026lt;/scriptu0026gt;"
},
{
"title": "Registration URL",
"startTimeSeconds": 790,
"endTimeSeconds": 795,
"language": "bash",
"code": "developer.apple.com/contact/request/siri-events"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10197/4/FD55A473-26AA-4BE5-896E-D18F043D0EB4/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10197/4/FD55A473-26AA-4BE5-896E-D18F043D0EB4/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10197/4/FD55A473-26AA-4BE5-896E-D18F043D0EB4/transcripts/wwdc2020-10197-transcripts.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10197/4/FD55A473-26AA-4BE5-896E-D18F043D0EB4/wwdc2020_10197_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10197/4/FD55A473-26AA-4BE5-896E-D18F043D0EB4/wwdc2020_10197_sd.mp4",
"duration": 1770
},
"related": {
"activities": [
"wwdc2020-10068",
"wwdc2020-10069",
"wwdc2020-10086",
"wwdc2020-10087",
"wwdc2020-10088",
"wwdc2020-10200",
"wwdc2020-10203",
"wwdc2020-10918",
"wwdc2020-10980",
"wwdc2019-243"
],
"resources": [
1338,
1217,
1216,
548
]
}
},
{
"id": "wwdc2020-10036",
"staticContentId": 3574,
"eventContentId": 10036,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10036",
"description": "Take your widget to the next level as we embark upon the third and final stage of the widgets code-along. Pick up where you left off in Part 2 or start with the Part 3 starter project to go warp speed ahead. We’ll explore advanced concepts for widgets, timelines, and configuration. Learn how to load in-process and background URLs and link directly to content within your app. And discover how to create multiple widgets that explore different features within your app, as well as making your widget dynamically configurable.\r\n\r\nFor more on creating great widgets, watch \"Build SwiftUI views for widgets”.",
"title": "Widgets Code-along, part 3: Advancing timelines",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS"
],
"keywords": [
"dynamic configuration",
"multiple widgets",
"onbackgroundurlsessionevents",
"swiftui",
"url sessions",
"widget",
"widgetbundle",
"widgetkit"
],
"topicIds": [
36,
22,
13
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10036/3/7DCA777C-43D0-4737-B04C-3D232B54A481/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10036/3/7DCA777C-43D0-4737-B04C-3D232B54A481/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10036/3/7DCA777C-43D0-4737-B04C-3D232B54A481/transcripts/wwdc2020-10036-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10036/3/7DCA777C-43D0-4737-B04C-3D232B54A481/wwdc2020_10036_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10036/3/7DCA777C-43D0-4737-B04C-3D232B54A481/wwdc2020_10036_sd.mp4",
"duration": 546
},
"related": {
"activities": [
"wwdc2020-10028",
"wwdc2020-10033",
"wwdc2020-10034",
"wwdc2020-10035",
"wwdc2020-10041",
"wwdc2020-10194"
],
"resources": [
1161,
1160,
810
]
}
},
{
"id": "wwdc2020-10015",
"staticContentId": 3812,
"eventContentId": 10015,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=n9igoal7",
"description": "",
"title": "Advancements in AVFoundation",
"articleID": "21371DEF-ED3D-4C0F-A2E8-7C71EFB2628F",
"articlePermalinkKey": "n9igoal7",
"originalPublishingDate": "2020-06-22T00:00:52-07:00",
"publishingExpiryDate": "2025-06-22T02:18:38-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS"
],
"keywords": [
"avfoundation",
"coremedia",
"core media",
"editing",
"export",
"hdr",
"playback",
"video",
"videotoolbox"
],
"topicIds": [
31,
30,
29
],
"type": "Article",
"images": [
"square",
"wide"
],
"related": {
"activities": [
"wwdc2020-10009",
"wwdc2020-10010",
"wwdc2020-10011",
"wwdc2020-10090",
"wwdc2020-10802",
"wwdc2020-10803",
"wwdc2020-10804"
]
}
},
{
"id": "wwdc2020-10158",
"staticContentId": 3679,
"eventContentId": 10158,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10158",
"description": "Discover techniques for streaming high-quality audio to bandwidth-limited networks and new audio codec support. We’ll share some best practices for supporting the xHE-AAC, FLAC, and Apple Lossless Audio audio codecs, including limited support for multichannel AAC.",
"title": "Deliver a better HLS audio experience",
"originalPublishingDate": "2020-06-26T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"topicIds": [
28,
31
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10158/5/1244B634-C720-4325-A806-A201BFDF5E51/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10158/5/1244B634-C720-4325-A806-A201BFDF5E51/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10158/5/1244B634-C720-4325-A806-A201BFDF5E51/transcripts/wwdc2020-10158-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10158/5/1244B634-C720-4325-A806-A201BFDF5E51/wwdc2020_10158_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10158/5/1244B634-C720-4325-A806-A201BFDF5E51/wwdc2020_10158_sd.mp4",
"duration": 1197
},
"related": {
"activities": [
"wwdc2020-10225",
"wwdc2020-10230",
"wwdc2020-10636",
"wwdc2020-10847",
"wwdc2020-10851"
],
"resources": [
1231,
1230,
175
]
}
},
{
"id": "wwdc2020-10748",
"staticContentId": 3616,
"eventContentId": 10748,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=kc9ys1yr",
"description": "",
"title": "Take Swift Playgrounds to the next level",
"articleID": "0BBC3CD8-7B72-404F-83D5-F96ED4824822",
"articlePermalinkKey": "kc9ys1yr",
"originalPublishingDate": "2020-06-22T00:00:56-07:00",
"publishingExpiryDate": "2025-06-22T01:12:10-07:00",
"topicIds": [
],
"type": "Article",
"images": [
"square",
"wide"
]
},
{
"id": "wwdc2020-10229",
"staticContentId": 3706,
"eventContentId": 10229,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10229",
"description": "Learn how to implement Blocking Preload Hints for Low-Latency HLS to reduce delivery latency and improve the reliability of your video and audio streams. Discover how to integrate LL-HLS with CMAF Chunk delivery and unify your delivery across streaming formats.",
"title": "Discover HLS Blocking Preload Hints",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"topicIds": [
31,
28
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10229/8/F033AE2E-6D7C-493D-B69F-666634C4E10B/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10229/8/F033AE2E-6D7C-493D-B69F-666634C4E10B/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10229/7/B77A61E7-0347-49D1-A262-FED0F213F31E/transcripts/wwdc2020-10229-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10229/8/F033AE2E-6D7C-493D-B69F-666634C4E10B/wwdc2020_10229_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10229/8/F033AE2E-6D7C-493D-B69F-666634C4E10B/wwdc2020_10229_sd.mp4",
"duration": 567
},
"related": {
"activities": [
"wwdc2020-10228",
"wwdc2020-10230",
"wwdc2020-10231",
"wwdc2020-10232",
"wwdc2020-10847",
"wwdc2020-10851"
],
"resources": [
1255,
1254
]
}
},
{
"id": "wwdc2020-10049",
"staticContentId": 3379,
"eventContentId": 10049,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10049",
"description": "Time is of the essence: Discover how your Apple Watch complications can provide relevant information throughout the day and help people get the information they need, when they need it. Learn best practices for capitalizing on your app’s runtime opportunities, incorporating APIs like background app refresh and URLSession, and implementing well-timed push notifications.",
"title": "Keep your complications up to date",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"watchOS"
],
"keywords": [
"🪁",
"⌚️",
"clockkit",
"urlsession",
"watchkit",
"watchos"
],
"topicIds": [
22,
18
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "updateActiveComplications",
"startTimeSeconds": 212,
"endTimeSeconds": 235,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eExtensionDelegateu003c/spanu003e: u003cspan class=\"syntax-title\"u003eNSObjectu003c/spanu003e, u003cspan class=\"syntax-title\"u003eWKExtensionDelegateu003c/spanu003e u003c/spanu003e{\n\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eupdateActiveComplicationsu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e complicationServer = u003cspan class=\"syntax-type\"u003eCLKComplicationServeru003c/spanu003e.sharedInstance()\n\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e activeComplications = complicationServer.activeComplications {\n\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e complication u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e activeComplications {\n\n complicationServer.reloadTimeline(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: complication)\n\n }\n } \n }\n}"
},
{
"title": "getCurrentTimelineEntry",
"startTimeSeconds": 266,
"endTimeSeconds": 294,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eComplicationControlleru003c/spanu003e: u003cspan class=\"syntax-title\"u003eNSObjectu003c/spanu003e, u003cspan class=\"syntax-title\"u003eCLKComplicationDataSourceu003c/spanu003e u003c/spanu003e{\n\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003egetCurrentTimelineEntryu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e complication: CLKComplication, \n withHandler handler: @escaping u003cspan class=\"syntax-params\"u003e(CLKComplicationTimelineEntry?)u003c/spanu003eu003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e) {\n\n u003cspan class=\"syntax-keyword\"u003eswitchu003c/spanu003e (complication.family) {\n \n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .modularSmall:\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e template = u003cspan class=\"syntax-type\"u003eCLKComplicationTemplateModularLargeTallBodyu003c/spanu003e.u003cspan class=\"syntax-keyword\"u003einitu003c/spanu003e(\n headerTextProvider: headerTextProvider, \n bodyTextProvider: bodyTextProvider)\n\n entry = u003cspan class=\"syntax-type\"u003eCLKComplicationTimelineEntryu003c/spanu003e(date: u003cspan class=\"syntax-type\"u003eDateu003c/spanu003e(), \n complicationTemplate: template)\n }\n\n handler(entry)\n }\n}"
},
{
"title": "scheduleBar",
"startTimeSeconds": 366,
"endTimeSeconds": 410,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eprivateu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003escheduleBARu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e first: Bool)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e now = u003cspan class=\"syntax-type\"u003eDateu003c/spanu003e()\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e scheduledDate = now.addingTimeInterval(first ? u003cspan class=\"syntax-number\"u003e60u003c/spanu003e : u003cspan class=\"syntax-number\"u003e15u003c/spanu003e*u003cspan class=\"syntax-number\"u003e60u003c/spanu003e)\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e info:u003cspan class=\"syntax-type\"u003eNSDictionaryu003c/spanu003e = [“submissionDate”:now]\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e wkExt = u003cspan class=\"syntax-type\"u003eWKExtensionu003c/spanu003e.shared()\n wkExt.scheduleBackgroundRefresh(withPreferredDate: scheduledDate, userInfo:info)\n { (error: u003cspan class=\"syntax-type\"u003eError?u003c/spanu003e) u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e (error != u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e) {\n u003cspan class=\"syntax-built_in\"u003eprintu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"background refresh could not be scheduled \\(error.debugDescription)\"u003c/spanu003e)\n } \n }\n }"
},
{
"title": "handleBAR",
"startTimeSeconds": 428,
"endTimeSeconds": 499,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eExtensionDelegateu003c/spanu003e: u003cspan class=\"syntax-title\"u003eNSObjectu003c/spanu003e, u003cspan class=\"syntax-title\"u003eWKExtensionDelegateu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ehandleu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e backgroundTasks: Setu0026lt;WKRefreshBackgroundTasku0026gt;)u003c/spanu003eu003c/spanu003e {\n\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e task u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e backgroundTasks {\n\n u003cspan class=\"syntax-keyword\"u003eswitchu003c/spanu003e task {\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e backgroundTask u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e u003cspan class=\"syntax-type\"u003eWKApplicationRefreshBackgroundTasku003c/spanu003e:\n\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e userInfo:u003cspan class=\"syntax-type\"u003eNSDictionaryu003c/spanu003e = backgroundTask.userInfo u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e? u003cspan class=\"syntax-type\"u003eNSDictionaryu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e then:u003cspan class=\"syntax-type\"u003eDateu003c/spanu003e = userInfo[u003cspan class=\"syntax-string\"u003e\"submissionDate\"u003c/spanu003e] u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e! u003cspan class=\"syntax-type\"u003eDateu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e interval = u003cspan class=\"syntax-type\"u003eDateu003c/spanu003e.u003cspan class=\"syntax-keyword\"u003einitu003c/spanu003e().timeIntervalSince(then)\n u003cspan class=\"syntax-built_in\"u003eprintu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"interval since request was made \\(interval)\"u003c/spanu003e)\n }\n }\n\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.updateActiveComplications()\n\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.scheduleBAR(first: u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e)\n\n backgroundTask.setTaskCompletedWithSnapshot(u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e)"
},
{
"title": "handleBAR (DataProvider)",
"startTimeSeconds": 527,
"endTimeSeconds": 551,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eExtensionDelegateu003c/spanu003e: u003cspan class=\"syntax-title\"u003eNSObjectu003c/spanu003e, u003cspan class=\"syntax-title\"u003eWKExtensionDelegateu003c/spanu003e u003c/spanu003e{\n\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e healthDataProvider: u003cspan class=\"syntax-type\"u003eHealthDataProvideru003c/spanu003e\n\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ehandleu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e backgroundTasks: Setu0026lt;WKRefreshBackgroundTasku0026gt;)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e task u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e backgroundTasks {\n u003cspan class=\"syntax-keyword\"u003eswitchu003c/spanu003e task {\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e backgroundTask u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e u003cspan class=\"syntax-type\"u003eWKApplicationRefreshBackgroundTasku003c/spanu003e:\n\n healthDataProvider.refresh() { (update: u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e) -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e update {\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.updateActiveComplications()\n }\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.scheduleBAR(first: u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e)\n backgroundTask.setTaskCompletedWithSnapshot(u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e)\n }"
},
{
"title": "Instantiate backgroundURLSession",
"startTimeSeconds": 695,
"endTimeSeconds": 719,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eWeatherDataProvideru003c/spanu003e : u003cspan class=\"syntax-title\"u003eNSObjectu003c/spanu003e, u003cspan class=\"syntax-title\"u003eURLSessionDownloadDelegateu003c/spanu003e u003c/spanu003e{\n\n u003cspan class=\"syntax-keyword\"u003eprivateu003c/spanu003e u003cspan class=\"syntax-built_in\"u003elazyu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e backgroundURLSession: u003cspan class=\"syntax-type\"u003eURLSessionu003c/spanu003e = {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e config = u003cspan class=\"syntax-type\"u003eURLSessionConfigurationu003c/spanu003e.background(withIdentifier: “u003cspan class=\"syntax-type\"u003eBackgroundWeatheru003c/spanu003eu003cspan class=\"syntax-string\"u003e\")\n config.isDiscretionary = false\n config.sessionSendsLaunchEvents = true\n\n return URLSession(configuration: config, delegate: self, delegateQueue: nil)\n }()u003c/spanu003e"
},
{
"title": "Schedule backgroundURLSessionTask",
"startTimeSeconds": 722,
"endTimeSeconds": 756,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003escheduleu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e first: Bool)u003c/spanu003eu003c/spanu003e {\n\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e backgroundTask == u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e {\n\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e url = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.currentWeatherURLForLocation(delegate.currentLocationCoordinate)\n {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e bgTask = backgroundURLSession.downloadTask(with: url)\n\n bgTask.earliestBeginDate = u003cspan class=\"syntax-type\"u003eDateu003c/spanu003e().addingTimeInterval(first ? u003cspan class=\"syntax-number\"u003e60u003c/spanu003e : u003cspan class=\"syntax-number\"u003e15u003c/spanu003e*u003cspan class=\"syntax-number\"u003e60u003c/spanu003e)\n\n bgTask.countOfBytesClientExpectsToSend = u003cspan class=\"syntax-number\"u003e200u003c/spanu003e\n bgTask.countOfBytesClientExpectsToReceive = u003cspan class=\"syntax-number\"u003e1024u003c/spanu003e\n\n bgTask.resume()\n\n backgroundTask = bgTask\n }\n }\n }\n}"
},
{
"title": "handle backgroundURLSession",
"startTimeSeconds": 809,
"endTimeSeconds": 836,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eExtensionDelegateu003c/spanu003e: u003cspan class=\"syntax-title\"u003eNSObjectu003c/spanu003e, u003cspan class=\"syntax-title\"u003eWKExtensionDelegateu003c/spanu003e u003c/spanu003e{\n\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e weatherDataProvider:u003cspan class=\"syntax-type\"u003eWeatherDataProvideru003c/spanu003e\n\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ehandleu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e backgroundTasks: Setu0026lt;WKRefreshBackgroundTasku0026gt;)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e task u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e backgroundTasks {\n u003cspan class=\"syntax-keyword\"u003eswitchu003c/spanu003e task {\n \n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e urlSessionTask u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e u003cspan class=\"syntax-type\"u003eWKURLSessionRefreshBackgroundTasku003c/spanu003e:\n\n weatherDataProvider.refresh() { (update: u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e) -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n weatherDataProvider.schedule(first: u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e)\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e update {\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.updateActiveComplications()\n }\n urlSessionTask.setTaskCompletedWithSnapshot(u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e)\n }"
},
{
"title": "handle backgroundURLSession",
"startTimeSeconds": 839,
"endTimeSeconds": 844,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eWeatherDataProvideru003c/spanu003e : u003cspan class=\"syntax-title\"u003eNSObjectu003c/spanu003e, u003cspan class=\"syntax-title\"u003eURLSessionDownloadDelegateu003c/spanu003e u003c/spanu003e{\n\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e completionHandler : ((u003cspan class=\"syntax-number\"u003e_u003c/spanu003e update: u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e) -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e)?\n\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003erefreshu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e completionHandler: @escaping u003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e update: Bool)u003c/spanu003eu003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e) {\n\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.completionHandler = completionHandler\n\n }"
},
{
"title": "didFinishDownloadingTo",
"startTimeSeconds": 848,
"endTimeSeconds": 861,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eWeatherDataProvideru003c/spanu003e : u003cspan class=\"syntax-title\"u003eNSObjectu003c/spanu003e, u003cspan class=\"syntax-title\"u003eURLSessionDownloadDelegateu003c/spanu003e u003c/spanu003e{\n\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eurlSessionu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e session: URLSession, downloadTask: URLSessionDownloadTask,\n didFinishDownloadingTo location: URL)u003c/spanu003eu003c/spanu003e {\n\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e location.isFileURL {\n u003cspan class=\"syntax-keyword\"u003edou003c/spanu003e {\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e jsonData = u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e u003cspan class=\"syntax-type\"u003eDatau003c/spanu003e(contentsOf: location)\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e kiteFlyingWeather = u003cspan class=\"syntax-type\"u003eKiteFlyingWeatheru003c/spanu003e(jsonData) {\n u003cspan class=\"syntax-comment\"u003e// Process weather data here.u003c/spanu003e\n }\n\n } u003cspan class=\"syntax-keyword\"u003ecatchu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e error u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e u003cspan class=\"syntax-type\"u003eNSErroru003c/spanu003e {\n u003cspan class=\"syntax-built_in\"u003eprintu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"could not read data from \\(location)\"u003c/spanu003e)\n }\n }\n }"
},
{
"title": "didComplete",
"startTimeSeconds": 863,
"endTimeSeconds": 881,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eurlSessionu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e session: URLSession, task: URLSessionTask, \n didCompleteWithError error: Error?)u003c/spanu003eu003c/spanu003e {\n\n u003cspan class=\"syntax-built_in\"u003eprintu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"session didCompleteWithError \\(error.debugDescription)”)\n\n DispatchQueue.main.async {\n\n self.completionHandler?(error == nil)\n\n self.completionHandler = nil\n\n }\n }\n}u003c/spanu003e"
},
{
"title": "Complication Pushes",
"startTimeSeconds": 1073,
"endTimeSeconds": 1179,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003ePushNotificationProvideru003c/spanu003e : u003cspan class=\"syntax-title\"u003eNSObjectu003c/spanu003e, u003cspan class=\"syntax-title\"u003ePKPushRegistryDelegateu003c/spanu003e u003c/spanu003e{\n\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003estartPushKitu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e pushRegistry = u003cspan class=\"syntax-type\"u003ePKPushRegistryu003c/spanu003e(queue: .main)\n pushRegistry.delegate = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e\n pushRegistry.desiredPushTypes = [.complication]\n }\n \n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003epushRegistryu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e registry: PKPushRegistry, \n didUpdate pushCredentials: PKPushCredentials, u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e type: PKPushType)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Send credentials to server u003c/spanu003e\n }\n \n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003epushRegistryu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e registry: PKPushRegistry, \n didReceiveIncomingPushWith payload: PKPushPayload, \n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e type: PKPushType, completion: @escaping u003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e) {\n u003cspan class=\"syntax-comment\"u003e// Process payloadu003c/spanu003e\n delegate.updateActiveComplications()\n completion()\n }"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10049/10/CD3717B4-610A-4738-8C94-A2B995381A44/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10049/10/CD3717B4-610A-4738-8C94-A2B995381A44/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10049/10/CD3717B4-610A-4738-8C94-A2B995381A44/transcripts/wwdc2020-10049-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10049/10/CD3717B4-610A-4738-8C94-A2B995381A44/wwdc2020_10049_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10049/10/CD3717B4-610A-4738-8C94-A2B995381A44/wwdc2020_10049_sd.mp4",
"duration": 1310
},
"related": {
"activities": [
"wwdc2020-10046",
"wwdc2020-10048",
"wwdc2020-10100",
"wwdc2020-10769",
"wwdc2020-10770"
],
"resources": [
971,
970,
882,
138,
9,
5
]
}
},
{
"id": "wwdc2020-10039",
"staticContentId": 3727,
"eventContentId": 10039,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10039",
"description": "Learn how to build a document-based app entirely in SwiftUI! We’ll walk you through the DocumentGroup API and how it composes with your App and Scenes, allowing you to add out-of-the-box support for document management — such as document browsing and standard commands — no heavy lifting required. You’ll learn to set up Universal Type Identifiers as well as gain understanding into what makes a top-notch document-based app.\r\n\r\nTo get the most out of this session, you should first familiarize yourself with building apps in SwiftUI. Check out \"App essentials in SwiftUI\" to learn more.",
"title": "Build document-based apps in SwiftUI",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS"
],
"keywords": [
"document",
"document app",
"document based app",
"document-based apps",
"documentgroup",
"exportedas",
"importedas",
"imported type identifier",
"windowgroup"
],
"topicIds": [
36,
22
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "DocumentGroup TextEditor",
"startTimeSeconds": 132,
"endTimeSeconds": 139,
"language": "swift",
"code": "@main\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eTextEditu003c/spanu003e: u003cspan class=\"syntax-title\"u003eAppu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eSceneu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eDocumentGroupu003c/spanu003e(newDocument: u003cspan class=\"syntax-type\"u003eTextDocumentu003c/spanu003e()) { file u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-type\"u003eTextEditoru003c/spanu003e(text: file.$document.text)\n }\n }\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10039/3/AB4F8C69-7A45-4CDB-A382-7D749ADB0891/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10039/3/AB4F8C69-7A45-4CDB-A382-7D749ADB0891/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10039/3/AB4F8C69-7A45-4CDB-A382-7D749ADB0891/transcripts/wwdc2020-10039-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10039/3/AB4F8C69-7A45-4CDB-A382-7D749ADB0891/wwdc2020_10039_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10039/3/AB4F8C69-7A45-4CDB-A382-7D749ADB0891/wwdc2020_10039_sd.mp4",
"duration": 722
},
"related": {
"activities": [
"wwdc2020-10037",
"wwdc2020-10041",
"wwdc2020-10699",
"wwdc2020-10700",
"wwdc2020-10701"
],
"resources": [
1275,
1274,
920,
751
]
}
},
{
"id": "wwdc2020-10167",
"staticContentId": 3866,
"eventContentId": 10167,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10167",
"description": "Come with us as we delve into unsafe pointer types in Swift. Discover the requirements for each type and how to use it correctly. We’ll discuss typed pointers, drop down to raw pointers, and finally circumvent pointer type safety entirely by binding memory.\r\n\r\nThis session is a follow-up to \"Unsafe Swift\" from WWDC20. To get the most out of it, you should be familiar with Swift and the C programming language.",
"title": "Safely manage pointers in Swift",
"originalPublishingDate": "2020-06-26T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"topicIds": [
36
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Images: undefined behavior can lead to data loss",
"startTimeSeconds": 344,
"endTimeSeconds": 424,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eImageu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-comment\"u003e// elided...u003c/spanu003e\n}\n\nu003cspan class=\"syntax-comment\"u003e// Undefined behavior can lead to data loss…u003c/spanu003e\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eCollageu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e imageData: u003cspan class=\"syntax-type\"u003eUnsafeMutablePointeru003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eImageu003c/spanu003eu0026gt;?\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e imageCount: u003cspan class=\"syntax-type\"u003eIntu003c/spanu003e = u003cspan class=\"syntax-number\"u003e0u003c/spanu003e\n}\n\nu003cspan class=\"syntax-comment\"u003e// C-style API expects a pointer-to-Intu003c/spanu003e\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eaddImagesu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e countPtr: UnsafeMutablePointeru0026lt;UInt32u0026gt;)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eUnsafeMutablePointeru003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eImageu003c/spanu003eu0026gt; {\n u003cspan class=\"syntax-comment\"u003e// ...u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e imageData = u003cspan class=\"syntax-type\"u003eUnsafeMutablePointeru003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eImageu003c/spanu003eu0026gt;.allocate(capacity: u003cspan class=\"syntax-number\"u003e1u003c/spanu003e)\n imageData[u003cspan class=\"syntax-number\"u003e0u003c/spanu003e] = u003cspan class=\"syntax-type\"u003eImageu003c/spanu003e()\n countPtr.pointee += u003cspan class=\"syntax-number\"u003e1u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e imageData\n}\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003esaveImagesu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e imageData: UnsafeMutablePointeru0026lt;Imageu0026gt;, u003cspan class=\"syntax-number\"u003e_u003c/spanu003e u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e: Int)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Arbitrary function body...u003c/spanu003e\n u003cspan class=\"syntax-built_in\"u003eprintu003c/spanu003e(u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e)\n}\n\nu003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e collage = u003cspan class=\"syntax-type\"u003eCollageu003c/spanu003e()\ncollage.imageData = u003cspan class=\"syntax-built_in\"u003ewithUnsafeMutablePointeru003c/spanu003e(to: u0026amp;collage.imageCount) {\n addImages(u003cspan class=\"syntax-type\"u003eUnsafeMutableRawPointeru003c/spanu003e($u003cspan class=\"syntax-number\"u003e0u003c/spanu003e).assumingMemoryBound(to: u003cspan class=\"syntax-type\"u003eUInt32u003c/spanu003e.u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e))\n}\nsaveImages(collage.imageData!, collage.imageCount) u003cspan class=\"syntax-comment\"u003e// May see imageCount == 0u003c/spanu003e"
},
{
"title": "Direct memory allocation",
"startTimeSeconds": 606,
"endTimeSeconds": 654,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003edirectAllocationu003c/spanu003eu0026lt;Tu0026gt;u003cspan class=\"syntax-params\"u003e(t: T, u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e: Int)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e tPtr = u003cspan class=\"syntax-type\"u003eUnsafeMutablePointeru003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eTu003c/spanu003eu0026gt;.allocate(capacity: u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e)\n tPtr.initialize(repeating: t, u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e: u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e)\n tPtr.assign(repeating: t, u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e: u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e)\n tPtr.deinitialize(u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e: u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e)\n tPtr.deallocate()\n}"
},
{
"title": "Using a raw pointer to read from Foundation Data",
"startTimeSeconds": 864,
"endTimeSeconds": 876,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e Foundation\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ereadUInt32u003c/spanu003eu003cspan class=\"syntax-params\"u003e(data: Data)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eUInt32u003c/spanu003e {\n data.withUnsafeBytes { (buffer: u003cspan class=\"syntax-type\"u003eUnsafeRawBufferPointeru003c/spanu003e) u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n buffer.load(fromByteOffset: u003cspan class=\"syntax-number\"u003e4u003c/spanu003e, u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e: u003cspan class=\"syntax-type\"u003eUInt32u003c/spanu003e.u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e)\n }\n}\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e data = u003cspan class=\"syntax-type\"u003eDatau003c/spanu003e(u003cspan class=\"syntax-type\"u003eArrayu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eUInt8u003c/spanu003eu0026gt;([u003cspan class=\"syntax-number\"u003e0u003c/spanu003e, u003cspan class=\"syntax-number\"u003e0u003c/spanu003e, u003cspan class=\"syntax-number\"u003e0u003c/spanu003e, u003cspan class=\"syntax-number\"u003e0u003c/spanu003e, u003cspan class=\"syntax-number\"u003e1u003c/spanu003e, u003cspan class=\"syntax-number\"u003e0u003c/spanu003e, u003cspan class=\"syntax-number\"u003e0u003c/spanu003e, u003cspan class=\"syntax-number\"u003e0u003c/spanu003e]))\nu003cspan class=\"syntax-built_in\"u003eprintu003c/spanu003e(readUInt32(data: data))"
},
{
"title": "Raw allocation",
"startTimeSeconds": 877,
"endTimeSeconds": 926,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003erawAllocateu003c/spanu003eu0026lt;Tu0026gt;u003cspan class=\"syntax-params\"u003e(t: T, numValues: Int)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eUnsafeMutablePointeru003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eTu003c/spanu003eu0026gt; {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e rawPtr = u003cspan class=\"syntax-type\"u003eUnsafeMutableRawPointeru003c/spanu003e.allocate(\n byteCount: u003cspan class=\"syntax-type\"u003eMemoryLayoutu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eTu003c/spanu003eu0026gt;.u003cspan class=\"syntax-built_in\"u003estrideu003c/spanu003e * numValues,\n alignment: u003cspan class=\"syntax-type\"u003eMemoryLayoutu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eTu003c/spanu003eu0026gt;.alignment)\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e tPtr = rawPtr.initializeMemory(u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e: u003cspan class=\"syntax-type\"u003eTu003c/spanu003e.u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e, repeating: t, u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e: numValues)\n u003cspan class=\"syntax-comment\"u003e// Must use the typed pointer ‘tPtr’ to deinitialize.u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e tPtr\n}"
},
{
"title": "Contiguous allocation",
"startTimeSeconds": 943,
"endTimeSeconds": 975,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003econtiguousAllocateu003c/spanu003eu0026lt;Headeru0026gt;u003cspan class=\"syntax-params\"u003e(header: Header, numValues: Int)u003c/spanu003eu003c/spanu003e -u0026gt; (u003cspan class=\"syntax-type\"u003eUnsafeMutablePointeru003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eHeaderu003c/spanu003eu0026gt;, u003cspan class=\"syntax-type\"u003eUnsafeMutablePointeru003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eInt32u003c/spanu003eu0026gt;) {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e offset = u003cspan class=\"syntax-type\"u003eMemoryLayoutu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eHeaderu003c/spanu003eu0026gt;.u003cspan class=\"syntax-built_in\"u003estrideu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e byteCount = offset + u003cspan class=\"syntax-type\"u003eMemoryLayoutu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eInt32u003c/spanu003eu0026gt;.u003cspan class=\"syntax-built_in\"u003estrideu003c/spanu003e * numValues\n u003cspan class=\"syntax-built_in\"u003eassertu003c/spanu003e(u003cspan class=\"syntax-type\"u003eMemoryLayoutu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eHeaderu003c/spanu003eu0026gt;.alignment u0026gt;= u003cspan class=\"syntax-type\"u003eMemoryLayoutu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eInt32u003c/spanu003eu0026gt;.alignment)\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e bufferPtr = u003cspan class=\"syntax-type\"u003eUnsafeMutableRawPointeru003c/spanu003e.allocate(\n byteCount: byteCount, alignment: u003cspan class=\"syntax-type\"u003eMemoryLayoutu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eHeaderu003c/spanu003eu0026gt;.alignment)\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e headerPtr = bufferPtr.initializeMemory(u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e: u003cspan class=\"syntax-type\"u003eHeaderu003c/spanu003e.u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e, repeating: header, u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e: u003cspan class=\"syntax-number\"u003e1u003c/spanu003e)\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e elementPtr = (bufferPtr + offset).initializeMemory(u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e: u003cspan class=\"syntax-type\"u003eInt32u003c/spanu003e.u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e, repeating: u003cspan class=\"syntax-number\"u003e0u003c/spanu003e, u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e: numValues)\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e (headerPtr, elementPtr)\n}"
},
{
"title": "Using assumingMemoryBound(to:) to recover a typed pointer",
"startTimeSeconds": 1083,
"endTimeSeconds": 1117,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003etakesIntPointeru003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e: UnsafePointeru0026lt;Intu0026gt;)u003c/spanu003eu003c/spanu003e { u003cspan class=\"syntax-comment\"u003e/* elided */u003c/spanu003e }\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eRawContaineru003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e rawPtr: u003cspan class=\"syntax-type\"u003eUnsafeRawPointeru003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e pointsToInt: u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e\n}\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003etestContaineru003c/spanu003eu003cspan class=\"syntax-params\"u003e(numValues: Int)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e intPtr = u003cspan class=\"syntax-type\"u003eUnsafeMutablePointeru003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eIntu003c/spanu003eu0026gt;.allocate(capacity: numValues)\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e rc = u003cspan class=\"syntax-type\"u003eRawContaineru003c/spanu003e(rawPtr: intPtr, pointsToInt: u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e)\n u003cspan class=\"syntax-comment\"u003e// ...u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e rc.pointsToInt {\n takesIntPointer(rc.rawPtr.assumingMemoryBound(to: u003cspan class=\"syntax-type\"u003eIntu003c/spanu003e.u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e))\n }\n}"
},
{
"title": "Calling pthread_create",
"startTimeSeconds": 1120,
"endTimeSeconds": 1158,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Use assumingMemoryBound to recover a pointer type from a (void *) C callback.u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e/*\nfunc pthread_create(_ thread: UnsafeMutablePointeru0026lt;pthread_t?u0026gt;!,\n _ attr: UnsafePointeru0026lt;pthread_attr_tu0026gt;?,\n _ start_routine: (UnsafeMutableRawPointer) -u0026gt; UnsafeMutableRawPointer?,\n _ arg: UnsafeMutableRawPointer?) -u0026gt; Int32\n*/u003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e Darwin\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eThreadContextu003c/spanu003e u003c/spanu003e{ u003cspan class=\"syntax-comment\"u003e/* elided */u003c/spanu003e }\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003etestPthreadCreateu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e contextPtr = u003cspan class=\"syntax-type\"u003eUnsafeMutablePointeru003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eThreadContextu003c/spanu003eu0026gt;.allocate(capacity: u003cspan class=\"syntax-number\"u003e1u003c/spanu003e)\n contextPtr.initialize(to: u003cspan class=\"syntax-type\"u003eThreadContextu003c/spanu003e())\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e pthread: pthread_t?\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e result = pthread_create(\n u0026amp;pthread, u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e,\n { (ptr: u003cspan class=\"syntax-type\"u003eUnsafeMutableRawPointeru003c/spanu003e) u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e contextPtr = ptr.assumingMemoryBound(to: u003cspan class=\"syntax-type\"u003eThreadContextu003c/spanu003e.u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e)\n u003cspan class=\"syntax-comment\"u003e// ... The rest of the thread start routineu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e\n },\n contextPtr)\n}"
},
{
"title": "Pointing to tuple elements",
"startTimeSeconds": 1166,
"endTimeSeconds": 1223,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003etakesIntPointeru003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e: UnsafePointeru0026lt;Intu0026gt;)u003c/spanu003eu003c/spanu003e { u003cspan class=\"syntax-comment\"u003e/* elided */u003c/spanu003e }\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003etestPointingToTupleu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e tuple = (u003cspan class=\"syntax-number\"u003e0u003c/spanu003e, u003cspan class=\"syntax-number\"u003e1u003c/spanu003e, u003cspan class=\"syntax-number\"u003e2u003c/spanu003e)\n u003cspan class=\"syntax-built_in\"u003ewithUnsafePointeru003c/spanu003e(to: tuple) { (tuplePtr: u003cspan class=\"syntax-type\"u003eUnsafePointeru003c/spanu003eu0026lt;(u003cspan class=\"syntax-type\"u003eIntu003c/spanu003e, u003cspan class=\"syntax-type\"u003eIntu003c/spanu003e, u003cspan class=\"syntax-type\"u003eIntu003c/spanu003e)u0026gt;) u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n takesIntPointer(u003cspan class=\"syntax-type\"u003eUnsafeRawPointeru003c/spanu003e(tuplePtr).assumingMemoryBound(to: u003cspan class=\"syntax-type\"u003eIntu003c/spanu003e.u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e))\n }\n}"
},
{
"title": "Pointing to struct properties",
"startTimeSeconds": 1226,
"endTimeSeconds": 1263,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003etakesIntPointeru003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e: UnsafePointeru0026lt;Intu0026gt;)u003c/spanu003eu003c/spanu003e { u003cspan class=\"syntax-comment\"u003e/* elided */u003c/spanu003e }\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eMyStructu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e status: u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e value: u003cspan class=\"syntax-type\"u003eIntu003c/spanu003e\n}\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003etestPointingToStructPropertyu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e myStruct = u003cspan class=\"syntax-type\"u003eMyStructu003c/spanu003e(status: u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e, value: u003cspan class=\"syntax-number\"u003e0u003c/spanu003e)\n u003cspan class=\"syntax-built_in\"u003ewithUnsafePointeru003c/spanu003e(to: myStruct) { (ptr: u003cspan class=\"syntax-type\"u003eUnsafePointeru003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eMyStructu003c/spanu003eu0026gt;) u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e rawValuePtr =\n (u003cspan class=\"syntax-type\"u003eUnsafeRawPointeru003c/spanu003e(ptr) + u003cspan class=\"syntax-type\"u003eMemoryLayoutu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eMyStructu003c/spanu003eu0026gt;.offset(of: \\u003cspan class=\"syntax-type\"u003eMyStructu003c/spanu003e.value)!)\n takesIntPointer(rawValuePtr.assumingMemoryBound(to: u003cspan class=\"syntax-type\"u003eIntu003c/spanu003e.u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e))\n }\n}"
},
{
"title": "bindMemory(to:capacity:) invalidates pointers",
"startTimeSeconds": 1277,
"endTimeSeconds": 1331,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003etestBindMemoryu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e uint16Ptr = u003cspan class=\"syntax-type\"u003eUnsafeMutablePointeru003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eUInt16u003c/spanu003eu0026gt;.allocate(capacity: u003cspan class=\"syntax-number\"u003e2u003c/spanu003e)\n uint16Ptr.initialize(repeating: u003cspan class=\"syntax-number\"u003e0u003c/spanu003e, u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e: u003cspan class=\"syntax-number\"u003e2u003c/spanu003e)\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e int32Ptr = u003cspan class=\"syntax-type\"u003eUnsafeMutableRawPointeru003c/spanu003e(uint16Ptr).bindMemory(to: u003cspan class=\"syntax-type\"u003eInt32u003c/spanu003e.u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e, capacity: u003cspan class=\"syntax-number\"u003e1u003c/spanu003e)\n u003cspan class=\"syntax-comment\"u003e// Accessing uint16Ptr is now undefinedu003c/spanu003e\n int32Ptr.deallocate()\n}"
},
{
"title": "withMemoryRebound(to:capacity:) API",
"startTimeSeconds": 1393,
"endTimeSeconds": 1441,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003etakesUInt8Pointeru003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e: UnsafePointeru0026lt;UInt8u0026gt;)u003c/spanu003eu003c/spanu003e { u003cspan class=\"syntax-comment\"u003e/* elided */u003c/spanu003e }\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003etestWithMemoryReboundu003c/spanu003eu003cspan class=\"syntax-params\"u003e(int8Ptr: UnsafePointeru0026lt;Int8u0026gt;, u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e: Int)u003c/spanu003eu003c/spanu003e {\n int8Ptr.withMemoryRebound(to: u003cspan class=\"syntax-type\"u003eUInt8u003c/spanu003e.u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e, capacity: u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e) {\n (uint8Ptr: u003cspan class=\"syntax-type\"u003eUnsafePointeru003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eUInt8u003c/spanu003eu0026gt;) u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// int8Ptr cannot be used within this closureu003c/spanu003e\n takesUInt8Pointer(uint8Ptr)\n }\n u003cspan class=\"syntax-comment\"u003e// uint8Ptr cannot be used outside this closureu003c/spanu003e\n}"
},
{
"title": "BufferView: Layering types on top of raw memory",
"startTimeSeconds": 1549,
"endTimeSeconds": 1592,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eUnsafeBufferViewu003c/spanu003eu0026lt;u003cspan class=\"syntax-title\"u003eElementu003c/spanu003eu0026gt;: u003cspan class=\"syntax-title\"u003eRandomAccessCollectionu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e rawBytes: u003cspan class=\"syntax-type\"u003eUnsafeRawBufferPointeru003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e: u003cspan class=\"syntax-type\"u003eIntu003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003einitu003c/spanu003e(reinterpret rawBytes: u003cspan class=\"syntax-type\"u003eUnsafeRawBufferPointeru003c/spanu003e, u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e: u003cspan class=\"syntax-type\"u003eElementu003c/spanu003e.u003cspan class=\"syntax-type\"u003eTypeu003c/spanu003e) {\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.rawBytes = rawBytes\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e = rawBytes.u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e / u003cspan class=\"syntax-type\"u003eMemoryLayoutu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eElementu003c/spanu003eu0026gt;.u003cspan class=\"syntax-built_in\"u003estrideu003c/spanu003e\n u003cspan class=\"syntax-built_in\"u003epreconditionu003c/spanu003e(u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e * u003cspan class=\"syntax-type\"u003eMemoryLayoutu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eElementu003c/spanu003eu0026gt;.u003cspan class=\"syntax-built_in\"u003estrideu003c/spanu003e == rawBytes.u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e)\n u003cspan class=\"syntax-built_in\"u003epreconditionu003c/spanu003e(u003cspan class=\"syntax-type\"u003eIntu003c/spanu003e(bitPattern: rawBytes.baseAddress).isMultiple(of: u003cspan class=\"syntax-type\"u003eMemoryLayoutu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eElementu003c/spanu003eu0026gt;.alignment))\n }\n\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e startIndex: u003cspan class=\"syntax-type\"u003eIntu003c/spanu003e { u003cspan class=\"syntax-number\"u003e0u003c/spanu003e }\n\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e endIndex: u003cspan class=\"syntax-type\"u003eIntu003c/spanu003e { u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e }\n\n u003cspan class=\"syntax-keyword\"u003esubscriptu003c/spanu003e(index: u003cspan class=\"syntax-type\"u003eIntu003c/spanu003e) -u0026gt; u003cspan class=\"syntax-type\"u003eElementu003c/spanu003e {\n rawBytes.load(fromByteOffset: index * u003cspan class=\"syntax-type\"u003eMemoryLayoutu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eElementu003c/spanu003eu0026gt;.u003cspan class=\"syntax-built_in\"u003estrideu003c/spanu003e, u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e: u003cspan class=\"syntax-type\"u003eElementu003c/spanu003e.u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e)\n }\n}\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003etestBufferViewu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e array = [u003cspan class=\"syntax-number\"u003e0u003c/spanu003e,u003cspan class=\"syntax-number\"u003e1u003c/spanu003e,u003cspan class=\"syntax-number\"u003e2u003c/spanu003e,u003cspan class=\"syntax-number\"u003e3u003c/spanu003e]\n array.withUnsafeBytes {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e view = u003cspan class=\"syntax-type\"u003eUnsafeBufferViewu003c/spanu003e(reinterpret: $u003cspan class=\"syntax-number\"u003e0u003c/spanu003e, u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e: u003cspan class=\"syntax-type\"u003eUIntu003c/spanu003e.u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e)\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e val u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e view {\n u003cspan class=\"syntax-built_in\"u003eprintu003c/spanu003e(val)\n }\n }\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10167/3/5A7F9994-6332-4CE6-8132-10C43C01827B/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10167/3/5A7F9994-6332-4CE6-8132-10C43C01827B/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10167/3/5A7F9994-6332-4CE6-8132-10C43C01827B/transcripts/wwdc2020-10167-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10167/3/5A7F9994-6332-4CE6-8132-10C43C01827B/wwdc2020_10167_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10167/3/5A7F9994-6332-4CE6-8132-10C43C01827B/wwdc2020_10167_sd.mp4",
"duration": 1651
},
"related": {
"activities": [
"wwdc2020-10648"
],
"resources": [
1325,
1324,
782
]
}
},
{
"id": "wwdc2020-10190",
"staticContentId": 3785,
"eventContentId": 10190,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10190",
"description": "Shortcuts are a natural fit on Apple Watch, allowing people to get things done with just a tap — even from a complication. Bring your app’s intents to the wrist: We’ll help you optimize your shortcuts performance, understand how intents can be routed from watchOS to iOS, explore the latest interaction and presentation interfaces, and examine how the Shortcuts app manages shortcuts and intents for Apple Watch.",
"title": "Create quick interactions with Shortcuts on watchOS",
"originalPublishingDate": "2020-06-26T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"watchOS"
],
"keywords": [
"apple watch",
"complications",
"extensions",
"intents",
"intentsui",
"shortcuts",
"shortcuts app",
"siri",
"sirikit",
"watchos"
],
"topicIds": [
13,
21
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10190/4/4E8B17DE-486E-44AC-BC2C-EA4E4DB20E6E/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10190/4/4E8B17DE-486E-44AC-BC2C-EA4E4DB20E6E/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10190/4/4E8B17DE-486E-44AC-BC2C-EA4E4DB20E6E/transcripts/wwdc2020-10190-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10190/4/4E8B17DE-486E-44AC-BC2C-EA4E4DB20E6E/wwdc2020_10190_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10190/4/4E8B17DE-486E-44AC-BC2C-EA4E4DB20E6E/wwdc2020_10190_sd.mp4",
"duration": 696
},
"related": {
"activities": [
"wwdc2020-10053",
"wwdc2020-10060",
"wwdc2020-10061",
"wwdc2020-10068",
"wwdc2020-10069",
"wwdc2020-10071",
"wwdc2020-10073",
"wwdc2020-10074",
"wwdc2020-10083",
"wwdc2020-10084",
"wwdc2020-10086",
"wwdc2020-10087",
"wwdc2020-10088",
"wwdc2020-10200",
"wwdc2020-10203",
"wwdc2020-10839",
"wwdc2020-10877",
"wwdc2020-10878"
],
"resources": [
1293,
1292
]
}
},
{
"id": "wwdc2020-10641",
"staticContentId": 3347,
"eventContentId": 10641,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10641",
"description": "Access the photos and videos you need for your app while preserving privacy. With the new Limited Photos Library feature, people can directly control which photos and videos an app can access to protect their private content. We’ll explore how this feature may affect your app, and take you through alternatives like PHPicker.\r\n\r\nCheck out “Meet the New Photos Picker” to learn more about PHPicker and how this this fully private picker can help you avoid requiring full Photos Library access in your app.",
"title": "Handle the Limited Photos Library in your app",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS"
],
"keywords": [
"photokit",
"photo library",
"photos",
"photos api",
"picker",
"privacy"
],
"topicIds": [
30,
22,
19
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Query for authorization status",
"startTimeSeconds": 516,
"endTimeSeconds": 541,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e Photos\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e accessLevel: u003cspan class=\"syntax-type\"u003ePHAccessLevelu003c/spanu003e = .readWrite\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e authorizationStatus = u003cspan class=\"syntax-type\"u003ePHPhotoLibraryu003c/spanu003e.authorizationStatus(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: accessLevel)\n\nu003cspan class=\"syntax-keyword\"u003eswitchu003c/spanu003e authorizationStatus {\nu003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .limited:\n u003cspan class=\"syntax-built_in\"u003eprintu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"limited authorization granted\"u003c/spanu003e)\nu003cspan class=\"syntax-keyword\"u003edefaultu003c/spanu003e:\n u003cspan class=\"syntax-comment\"u003e//u003cspan class=\"syntax-doctag\"u003eFIXME:u003c/spanu003e Implement handling for all authorizationStatus valuesu003c/spanu003e\n u003cspan class=\"syntax-built_in\"u003eprintu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Not implemented\"u003c/spanu003e)\n}"
},
{
"title": "Request read/write authorization",
"startTimeSeconds": 583,
"endTimeSeconds": 633,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e Photos\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e requiredAccessLevel: u003cspan class=\"syntax-type\"u003ePHAccessLevelu003c/spanu003e = .readWrite\nu003cspan class=\"syntax-type\"u003ePHPhotoLibraryu003c/spanu003e.requestAuthorization(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: requiredAccessLevel) { authorizationStatus u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eswitchu003c/spanu003e authorizationStatus {\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .limited:\n u003cspan class=\"syntax-built_in\"u003eprintu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"limited authorization granted\"u003c/spanu003e)\n u003cspan class=\"syntax-keyword\"u003edefaultu003c/spanu003e:\n u003cspan class=\"syntax-comment\"u003e//u003cspan class=\"syntax-doctag\"u003eFIXME:u003c/spanu003e Implement handling for all authorizationStatusu003c/spanu003e\n u003cspan class=\"syntax-built_in\"u003eprintu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Unimplemented\"u003c/spanu003e)\n \n }\n}"
},
{
"title": "Present the limited library management UI",
"startTimeSeconds": 724,
"endTimeSeconds": 756,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e PhotosUI\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e library = u003cspan class=\"syntax-type\"u003ePHPhotoLibraryu003c/spanu003e.shared()\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e viewController = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e\n\nlibrary.presentLimitedLibraryPicker(from: viewController)"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10641/5/51B91C53-BFDD-41DD-9EA3-418DE396897F/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10641/5/51B91C53-BFDD-41DD-9EA3-418DE396897F/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10641/4/C149B921-AABB-42E4-9F4E-BCB9B2495225/transcripts/wwdc2020-10641-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10641/5/51B91C53-BFDD-41DD-9EA3-418DE396897F/wwdc2020_10641_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10641/5/51B91C53-BFDD-41DD-9EA3-418DE396897F/wwdc2020_10641_sd.mp4",
"duration": 857
},
"related": {
"activities": [
"wwdc2020-10652",
"wwdc2020-10676",
"wwdc2020-10793",
"wwdc2020-10794",
"wwdc2017-505"
],
"resources": [
939,
938,
374
]
}
},
{
"id": "wwdc2020-10139",
"staticContentId": 3685,
"eventContentId": 10139,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10139",
"description": "Empower your organization with the right tools while protecting privacy and security. Discover Apple’s identity management tools for enterprise, and how they can help you create a smoother experience for users when signing in to devices, apps and websites. We’ll show you how to take advantage of Federated Authentication and Single Sign-on extensions, including changes to Apple’s built-in Kerberos extension. And explore our other platform tools for enterprise users, including macOS account types and Shared iPad for Business.",
"title": "Leverage enterprise identity and authentication",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS"
],
"keywords": [
"authentication",
"enterprise",
"kerberos",
"mdm",
"sso",
"vpn"
],
"topicIds": [
44,
70
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Calling App Information",
"startTimeSeconds": 814,
"endTimeSeconds": 824,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e localizedCallerDisplayName: u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e\n \nu003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e callerTeamIdentifier: u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e isCallerManaged: u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e"
},
{
"title": "Profile Removal Operation",
"startTimeSeconds": 852,
"endTimeSeconds": 874,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// existing operationsu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003estaticu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e operationLogin: u003cspan class=\"syntax-type\"u003eASAuthorizationu003c/spanu003e.u003cspan class=\"syntax-type\"u003eOpenIDOperationu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003estaticu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e operationRefresh: u003cspan class=\"syntax-type\"u003eASAuthorizationu003c/spanu003e.u003cspan class=\"syntax-type\"u003eOpenIDOperationu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003estaticu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e operationLogout: u003cspan class=\"syntax-type\"u003eASAuthorizationu003c/spanu003e.u003cspan class=\"syntax-type\"u003eOpenIDOperationu003c/spanu003e\n\nu003cspan class=\"syntax-comment\"u003e//new this yearu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003estaticu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e configurationRemoved: u003cspan class=\"syntax-type\"u003eASAuthorizationProviderAuthorizationOperationu003c/spanu003e"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10139/5/EE9B8782-2114-4EDC-A2CF-C26D03BB5E54/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10139/5/EE9B8782-2114-4EDC-A2CF-C26D03BB5E54/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10139/5/EE9B8782-2114-4EDC-A2CF-C26D03BB5E54/transcripts/wwdc2020-10139-transcripts.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10139/5/EE9B8782-2114-4EDC-A2CF-C26D03BB5E54/wwdc2020_10139_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10139/5/EE9B8782-2114-4EDC-A2CF-C26D03BB5E54/wwdc2020_10139_sd.mp4",
"duration": 2106
},
"related": {
"activities": [
"wwdc2020-10223",
"wwdc2020-10638",
"wwdc2020-10639",
"wwdc2020-10754",
"wwdc2020-10844",
"tech-talks-301"
],
"resources": [
1239,
1238,
796,
584,
426,
330,
329,
146,
143
]
}
},
{
"id": "wwdc2020-20009",
"staticContentId": 4586,
"eventContentId": 20009,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=ls3g7su1",
"description": "",
"title": "Thursday",
"articleID": "165E1ABE-6308-47F9-B109-ABA483ED73CD",
"articlePermalinkKey": "ls3g7su1",
"originalPublishingDate": "2020-06-25T05:20:16-07:00",
"publishingExpiryDate": "2025-06-25T05:39:21-07:00",
"topicIds": [
],
"type": "Article",
"images": [
"square",
"wide"
]
},
{
"id": "wwdc2020-10737",
"staticContentId": 3399,
"eventContentId": 10737,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=w3zpokz1",
"description": "",
"title": "Health and fitness",
"articleID": "A3D4F659-2071-4E65-9D3E-5C5DC27CA0A2",
"articlePermalinkKey": "w3zpokz1",
"originalPublishingDate": "2020-06-22T05:43:40-07:00",
"publishingExpiryDate": "2025-06-22T05:46:23-07:00",
"platforms": [
"iOS",
"macOS",
"watchOS"
],
"topicIds": [
14
],
"type": "Article",
"images": [
"square",
"wide"
],
"related": {
"activities": [
"wwdc2020-10216"
]
}
},
{
"id": "wwdc2020-10068",
"staticContentId": 3640,
"eventContentId": 10068,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10068",
"description": "Get a quick overview of everything new in Siri and Shortcuts to help people get more out of your app: We’ll demonstrate how you can design visually rich conversations, feel at home with the operating system by designing for the new compact Siri UI, and provide an overview of all the ways we’ve made it even easier for people to organize and set up actions from your apps.",
"title": "What's new in SiriKit and Shortcuts",
"originalPublishingDate": "2020-06-23T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"watchOS"
],
"keywords": [
"automation",
"extensions",
"in-app intent handling",
"intents",
"intentsui",
"shortcuts",
"shortcuts app",
"siri",
"sirikit",
"voice",
"watchos",
"watchos design"
],
"topicIds": [
21,
13
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10068/6/21534713-4524-4D0D-B555-7E3C2D960F96/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10068/6/21534713-4524-4D0D-B555-7E3C2D960F96/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10068/6/21534713-4524-4D0D-B555-7E3C2D960F96/transcripts/wwdc2020-10068-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10068/6/21534713-4524-4D0D-B555-7E3C2D960F96/wwdc2020_10068_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10068/6/21534713-4524-4D0D-B555-7E3C2D960F96/wwdc2020_10068_sd.mp4",
"duration": 735
},
"related": {
"activities": [
"wwdc2020-10028",
"wwdc2020-10053",
"wwdc2020-10060",
"wwdc2020-10061",
"wwdc2020-10071",
"wwdc2020-10073",
"wwdc2020-10074",
"wwdc2020-10083",
"wwdc2020-10084",
"wwdc2020-10086",
"wwdc2020-10087",
"wwdc2020-10088",
"wwdc2020-10190",
"wwdc2020-10194",
"wwdc2020-10197",
"wwdc2020-10200",
"wwdc2020-10203",
"wwdc2020-10839",
"wwdc2020-10877",
"wwdc2020-10878",
"wwdc2020-10879"
],
"resources": [
1211,
1210,
893,
866,
350
]
}
},
{
"id": "wwdc2020-10967",
"staticContentId": 3445,
"eventContentId": 10967,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=b7gg4gdx",
"description": "",
"title": "What's new in Machine Learning and Computer Vision",
"articleID": "E0284D1F-4BA8-4732-86B0-C806EE26E7A4",
"articlePermalinkKey": "b7gg4gdx",
"originalPublishingDate": "2020-06-22T00:00:15-07:00",
"publishingExpiryDate": "2025-06-22T01:35:44-07:00",
"topicIds": [
],
"type": "Article",
"images": [
"square",
"wide"
]
},
{
"id": "wwdc2020-10791",
"staticContentId": 3423,
"eventContentId": 10791,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=lve6alo6",
"description": "",
"title": "Explore HLS streaming",
"articleID": "F01CDD5C-0DB5-4C51-8085-2A22116B64BB",
"articlePermalinkKey": "lve6alo6",
"originalPublishingDate": "2020-06-22T00:00:59-07:00",
"publishingExpiryDate": "2025-06-22T02:12:53-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS"
],
"topicIds": [
31,
28
],
"type": "Article",
"images": [
"square",
"wide"
],
"related": {
"activities": [
"wwdc2020-10847",
"wwdc2020-10851"
]
}
},
{
"id": "wwdc2020-10063",
"staticContentId": 3829,
"eventContentId": 10063,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10063",
"description": "Are you mystified about why and when your app gets background processing time? No need for a crystal ball! We’ll show you how to tackle the seven major factors that impact background runtime, and how you can integrate background modes that help your app come back to the foreground faster, run more smoothly, and reduce battery drain. \r\n\r\nLearn about the major factors affecting runtime for your app, the nuances of each opportunistic background mode, and how you can help your apps run more often and stay fresher by minimizing energy and data consumption.\r\n\r\nFor more information on background processing and execution, watch “Advances in App Background Execution” from WWDC19.",
"title": "Background execution demystified",
"originalPublishingDate": "2020-06-26T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS"
],
"keywords": [
"background",
"background runtime",
"push",
"urlsession"
],
"topicIds": [
35,
18
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10063/3/2E1C3BA0-2643-4330-A5B2-3A9878453987/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10063/3/2E1C3BA0-2643-4330-A5B2-3A9878453987/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10063/3/2E1C3BA0-2643-4330-A5B2-3A9878453987/transcripts/wwdc2020-10063-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10063/3/2E1C3BA0-2643-4330-A5B2-3A9878453987/wwdc2020_10063_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10063/3/2E1C3BA0-2643-4330-A5B2-3A9878453987/wwdc2020_10063_sd.mp4",
"duration": 1026
},
"related": {
"activities": [
"wwdc2020-10095",
"wwdc2020-10845",
"wwdc2019-707"
],
"resources": [
1319,
1318,
744,
733,
732
]
}
},
{
"id": "wwdc2020-20010",
"staticContentId": 4592,
"eventContentId": 20010,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=dmf99kjc",
"description": "",
"title": "WWDC20 Daily Digest: Thursday",
"articleID": "204E7299-6CFE-459B-BB94-112D1CC594E0",
"articlePermalinkKey": "dmf99kjc",
"originalPublishingDate": "2020-06-25T04:50:37-07:00",
"publishingExpiryDate": "2025-06-25T05:33:25-07:00",
"topicIds": [
],
"type": "Article",
"images": [
"square",
"wide"
]
},
{
"id": "wwdc2020-10181",
"staticContentId": 3660,
"eventContentId": 10181,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=v0n9qlqx",
"description": "",
"title": "The game developer’s toolkit",
"articleID": "61472F0F-C74A-4642-9481-AA151FED9218",
"articlePermalinkKey": "v0n9qlqx",
"originalPublishingDate": "2020-06-22T00:00:40-07:00",
"publishingExpiryDate": "2025-06-22T02:01:29-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS"
],
"keywords": [
"achievement",
"controller",
"controllers",
"dashboard",
"game",
"game best practices",
"game center",
"game center design",
"game controller",
"game controllers",
"game design",
"game designer",
"game dev",
"game developer",
"gamekit",
"game kit",
"gameplaykit",
"games",
"leaderboard"
],
"topicIds": [
26,
6,
3
],
"type": "Article",
"images": [
"square",
"wide"
],
"related": {
"activities": [
"wwdc2020-10675",
"wwdc2020-10685",
"wwdc2020-10808",
"wwdc2020-10810",
"wwdc2020-10818",
"wwdc2020-10830",
"wwdc2020-10831",
"wwdc2020-10832",
"wwdc2020-10833"
],
"resources": [
827
]
}
},
{
"id": "wwdc2020-10076",
"staticContentId": 3793,
"eventContentId": 10076,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10076",
"description": "Analyze aggregated power and performance data from multiple versions of your app with just a few clicks. We’ll introduce you to the latest version of the Xcode Organizer and its interactive interface, where you can easily compare and contrast app metrics across releases. Explore disk write diagnostics and scroll hitch metrics, and learn how you can use these to offer better performance, reduce battery consumption, and improve device health for people using your app.\r\n\r\nIf you’d like additional information on the Xcode Organizer and improving power and performance in your app, watch \"Improving Battery Life and Performance\" from WWDC19. For more on hitches, check out “Eliminate animation hitches with XCTest.”",
"title": "Diagnose performance issues with the Xcode Organizer",
"originalPublishingDate": "2020-06-26T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"keywords": [
"analytics",
"diagnostics",
"metrics",
"performance",
"xcode"
],
"topicIds": [
38,
35
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10076/4/2E98AB12-04C8-4D40-8FD1-BC186B322664/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10076/4/2E98AB12-04C8-4D40-8FD1-BC186B322664/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10076/4/2E98AB12-04C8-4D40-8FD1-BC186B322664/transcripts/wwdc2020-10076-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10076/4/2E98AB12-04C8-4D40-8FD1-BC186B322664/wwdc2020_10076_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10076/4/2E98AB12-04C8-4D40-8FD1-BC186B322664/wwdc2020_10076_sd.mp4",
"duration": 667
},
"related": {
"activities": [
"wwdc2020-10057",
"wwdc2020-10077",
"wwdc2020-10081",
"wwdc2020-10845",
"wwdc2020-10893",
"wwdc2020-10894"
],
"resources": [
1301,
1300
]
}
},
{
"id": "wwdc2020-10210",
"staticContentId": 3373,
"eventContentId": 10210,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10210",
"description": "Keep code out of the kernel and give your customers a more secure and reliable experience with accessories using DriverKit. Discover how to create low-level drivers that support PCI devices or SCSI controllers. And find out how you can achieve great performance with DriverKit on macOS Big Sur.",
"title": "Modernize PCI and SCSI drivers with DriverKit",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"macOS"
],
"keywords": [
"driver",
"extension",
"hid",
"kernel",
"networking",
"pci",
"scsi",
"serial",
"usb"
],
"topicIds": [
67
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10210/3/CD65DE89-E747-4A3E-A078-13ACD36B9B72/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10210/3/CD65DE89-E747-4A3E-A078-13ACD36B9B72/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10210/2/0E7F6CA4-A242-494E-9675-65D13F3B48A1/transcripts/wwdc2020-10210-transcripts.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10210/3/CD65DE89-E747-4A3E-A078-13ACD36B9B72/wwdc2020_10210_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10210/3/CD65DE89-E747-4A3E-A078-13ACD36B9B72/wwdc2020_10210_sd.mp4",
"duration": 2213
},
"related": {
"activities": [
"wwdc2020-10211",
"wwdc2020-10899",
"wwdc2019-702"
],
"resources": [
963,
962,
579
]
}
},
{
"id": "wwdc2020-10734",
"staticContentId": 3620,
"eventContentId": 10734,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=tjv7v7k1",
"description": "",
"title": "Swift deep dive",
"articleID": "DB4AAEEE-3EBC-401A-91B8-403BF7B54C35",
"articlePermalinkKey": "tjv7v7k1",
"originalPublishingDate": "2020-06-22T01:00:17-07:00",
"publishingExpiryDate": "2025-06-22T00:48:02-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"topicIds": [
36
],
"type": "Article",
"images": [
"square",
"wide"
],
"related": {
"activities": [
"wwdc2020-10638"
]
}
},
{
"id": "wwdc2020-10703",
"staticContentId": 3712,
"eventContentId": 10703,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=d9kd3m7g",
"description": "",
"title": "What's new in UIKit and iOS",
"articleID": "377030D4-6BA0-4F80-B8FA-D61777C033A6",
"articlePermalinkKey": "d9kd3m7g",
"originalPublishingDate": "2020-06-22T01:22:18-07:00",
"publishingExpiryDate": "2025-06-22T04:34:22-07:00",
"platforms": [
"iOS"
],
"topicIds": [
22
],
"type": "Article",
"images": [
"square",
"wide"
],
"related": {
"activities": [
"wwdc2020-10093",
"wwdc2020-10638",
"wwdc2020-10906",
"wwdc2020-10907",
"wwdc2020-10908"
]
}
},
{
"id": "wwdc2020-20001",
"staticContentId": 4553,
"eventContentId": 20001,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=cyq5clst",
"description": "",
"title": "Tuesday",
"articleID": "767C8D7B-A9D5-4747-96F2-862A3F8C1797",
"articlePermalinkKey": "cyq5clst",
"originalPublishingDate": "2020-06-23T09:00:56-07:00",
"publishingExpiryDate": "2025-06-22T21:11:26-07:00",
"topicIds": [
],
"type": "Article",
"images": [
"square",
"wide"
]
},
{
"id": "wwdc2020-10225",
"staticContentId": 3427,
"eventContentId": 10225,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10225",
"description": "Deliver live and on-demand audio and video to iPhone, iPad, Apple Watch, Mac, PC, and Apple TV with HTTP Live Streaming (HLS). Learn about tools and features to help improve the authoring of your HLS streams and provide low-latency delivery and better audio performance to people watching or listening to your content. We’ll also walk you through creating Low-Latency HLS test streams, integrating audio codecs, and creating master playlists.",
"title": "Improve stream authoring with HLS Tools",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"topicIds": [
31,
28
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10225/1/071CF9A2-F9B9-48A1-8D81-012721D0A52C/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10225/1/071CF9A2-F9B9-48A1-8D81-012721D0A52C/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10225/1/071CF9A2-F9B9-48A1-8D81-012721D0A52C/transcripts/wwdc2020-10225-transcripts.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10225/1/071CF9A2-F9B9-48A1-8D81-012721D0A52C/wwdc2020_10225_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10225/1/071CF9A2-F9B9-48A1-8D81-012721D0A52C/wwdc2020_10225_sd.mp4",
"duration": 641
},
"related": {
"activities": [
"wwdc2020-10158",
"wwdc2020-10228",
"wwdc2020-10230",
"wwdc2020-10231",
"wwdc2020-10694",
"wwdc2020-10847",
"wwdc2020-10851",
"wwdc2019-502"
]
}
},
{
"id": "wwdc2020-10018",
"staticContentId": 3826,
"eventContentId": 10018,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=5jn2wyhi",
"description": "",
"title": "Ray tracing and function pointers in Metal",
"articleID": "24306ACC-B8AE-4D01-A2F3-77AFC403EED4",
"articlePermalinkKey": "5jn2wyhi",
"originalPublishingDate": "2020-06-22T00:00:13-07:00",
"publishingExpiryDate": "2025-06-22T02:37:15-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS"
],
"keywords": [
"metal",
"metal shading language",
"ray tracing"
],
"topicIds": [
27,
26,
25,
24
],
"type": "Article",
"images": [
"square",
"wide"
],
"related": {
"activities": [
"wwdc2020-10012",
"wwdc2020-10013",
"wwdc2020-10811",
"wwdc2020-10812",
"wwdc2020-10813",
"wwdc2020-10815",
"wwdc2020-10816",
"wwdc2020-10817"
]
}
},
{
"id": "wwdc2020-10091",
"staticContentId": 3610,
"eventContentId": 10091,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10091",
"description": "Plan for failure: Design great tests to help you find and diagnose even the toughest bugs. Learn how to improve your automated tests with XCTest to find hidden issues in even the best code. We’ll explain how to prepare your tests for failure to make triaging issues easier, letting you solve interface issues and deliver fixes quickly.\r\n\r\nTo get the most out of this session, you should already be familiar with writing UI tests within the XCTest framework.\r\n\r\nFor more on testing tools, head over to “The suite life of testing”.",
"title": "Write tests to fail",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"keywords": [
"testing",
"xcode",
"xctest"
],
"topicIds": [
38,
37,
36
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Use setUpWithError()",
"startTimeSeconds": 118,
"endTimeSeconds": 184,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eRecipesTestsu003c/spanu003e: u003cspan class=\"syntax-title\"u003eXCTestCaseu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e app = u003cspan class=\"syntax-type\"u003eFrutaAppu003c/spanu003e()\n\n u003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003esetUpWithErroru003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e u003cspan class=\"syntax-keyword\"u003ethrowsu003c/spanu003e {\n continueAfterFailure = u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e\n app.launchArguments.append(u003cspan class=\"syntax-string\"u003e\"-recipes-tests\"u003c/spanu003e)\n app.launch()\n }\n}"
},
{
"title": "Use launch arguments",
"startTimeSeconds": 189,
"endTimeSeconds": 214,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eRecipesTestsu003c/spanu003e: u003cspan class=\"syntax-title\"u003eXCTestCaseu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e app = u003cspan class=\"syntax-type\"u003eFrutaAppu003c/spanu003e()\n\n u003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003esetUpWithErroru003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e u003cspan class=\"syntax-keyword\"u003ethrowsu003c/spanu003e {\n continueAfterFailure = u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e\n app.launchArguments.append(u003cspan class=\"syntax-string\"u003e\"-recipes-tests\"u003c/spanu003e)\n app.launch()\n }\n}\n\n@u003cspan class=\"syntax-type\"u003eStateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eprivateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e selection: u003cspan class=\"syntax-type\"u003eTabu003c/spanu003e = \n u003cspan class=\"syntax-type\"u003eCommandLineu003c/spanu003e.arguments.u003cspan class=\"syntax-built_in\"u003econtainsu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"-recipes-tests\"u003c/spanu003e) \n ? .recipes : .menu"
},
{
"title": "Design tests for a specific goal",
"startTimeSeconds": 252,
"endTimeSeconds": 284,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003etestIngredientsListAccuracyu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e u003cspan class=\"syntax-keyword\"u003ethrowsu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Select Berry Blue recipeu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e recipe = u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e \n app.smoothieList().selectRecipe\n (smoothie: .berryBlue)\n\n u003cspan class=\"syntax-comment\"u003e// Verify ingredients listu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e recipe.verify(ingredients: \n u003cspan class=\"syntax-type\"u003eSmoothieTypeu003c/spanu003e.berryBlue.ingredients)\n}"
},
{
"title": "Use enums for string values",
"startTimeSeconds": 296,
"endTimeSeconds": 312,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eenumu003c/spanu003e u003cspan class=\"syntax-title\"u003eSmoothieTypeu003c/spanu003e : u003cspan class=\"syntax-title\"u003eStringu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e berryBlue = u003cspan class=\"syntax-string\"u003e\"Berry Blue\"u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e carrotChops = u003cspan class=\"syntax-string\"u003e\"Carrot Chops\"u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e berryBananas = u003cspan class=\"syntax-string\"u003e\"That's Berry Bananas!\"u003c/spanu003e\n \n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e ingredients : [u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e] {\n u003cspan class=\"syntax-keyword\"u003eswitchu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .berryBlue:\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e [u003cspan class=\"syntax-string\"u003e\"Orange\"u003c/spanu003e, u003cspan class=\"syntax-string\"u003e\"Blueberry\"u003c/spanu003e, u003cspan class=\"syntax-string\"u003e\"Avocado\"u003c/spanu003e]\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .carrotChops:\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e [u003cspan class=\"syntax-string\"u003e\"Orange\"u003c/spanu003e, u003cspan class=\"syntax-string\"u003e\"Carrot\"u003c/spanu003e, u003cspan class=\"syntax-string\"u003e\"Mango\"u003c/spanu003e]\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .berryBananas:\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e [u003cspan class=\"syntax-string\"u003e\"Almond Milk\"u003c/spanu003e, u003cspan class=\"syntax-string\"u003e\"Banana\"u003c/spanu003e, u003cspan class=\"syntax-string\"u003e\"Strawberry\"u003c/spanu003e]\n }\n }\n}"
},
{
"title": "Factor common code",
"startTimeSeconds": 325,
"endTimeSeconds": 349,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e recipe = u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e app.smoothieList().selectRecipe(smoothie: .berryBlue)\n\nu003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eFrutaAppu003c/spanu003e : u003cspan class=\"syntax-title\"u003eXCUIApplicationu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003esmoothieListu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e u003cspan class=\"syntax-keyword\"u003ethrowsu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eSmoothieListu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e element = tables[u003cspan class=\"syntax-string\"u003e\"Smoothie List\"u003c/spanu003e]\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e !element.waitForExistence(timeout: u003cspan class=\"syntax-number\"u003e5u003c/spanu003e) {\n u003cspan class=\"syntax-keyword\"u003ethrowu003c/spanu003e u003cspan class=\"syntax-type\"u003eFrutaErroru003c/spanu003e.elementDoesNotExist(u003cspan class=\"syntax-string\"u003e\"Smoothie List table\"u003c/spanu003e)\n }\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-type\"u003eSmoothieListu003c/spanu003e(app: u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e, element: element)\n }\n} \n\nu003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eSmoothieListu003c/spanu003e : u003cspan class=\"syntax-title\"u003eFrutaUIElementu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eselectRecipeu003c/spanu003eu003cspan class=\"syntax-params\"u003e(smoothie: SmoothieType)u003c/spanu003eu003c/spanu003e u003cspan class=\"syntax-keyword\"u003ethrowsu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eRecipeu003c/spanu003e {\n element.buttons[smoothie.rawValue].tap()\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e app.recipe()\n }\n}"
},
{
"title": "Model UI hierarchy in testing code",
"startTimeSeconds": 349,
"endTimeSeconds": 392,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eFrutaAppu003c/spanu003e : u003cspan class=\"syntax-title\"u003eXCUIApplicationu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003esmoothieListu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e u003cspan class=\"syntax-keyword\"u003ethrowsu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eSmoothieListu003c/spanu003e {  }\n} \n\nu003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eSmoothieListu003c/spanu003e : u003cspan class=\"syntax-title\"u003eFrutaUIElementu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eselectRecipeu003c/spanu003eu003cspan class=\"syntax-params\"u003e(smoothie: SmoothieType)u003c/spanu003eu003c/spanu003e u003cspan class=\"syntax-keyword\"u003ethrowsu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eRecipeu003c/spanu003e {  }\n}\n\nu003cspan class=\"syntax-keyword\"u003eopenu003c/spanu003e u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e u003cspan class=\"syntax-title\"u003eFrutaUIElementu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e app: u003cspan class=\"syntax-type\"u003eFrutaAppu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e element: u003cspan class=\"syntax-type\"u003eXCUIElementu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003einitu003c/spanu003e(app: u003cspan class=\"syntax-type\"u003eFrutaAppu003c/spanu003e, element: u003cspan class=\"syntax-type\"u003eXCUIElementu003c/spanu003e) {\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.app = app\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.element = element\n }\n}"
},
{
"title": "Use assertion messages",
"startTimeSeconds": 497,
"endTimeSeconds": 506,
"language": "swift",
"code": "u003cspan class=\"syntax-type\"u003eXCTAssertEqualu003c/spanu003e(u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e, expectedCount, u003cspan class=\"syntax-string\"u003e\"\\(SmoothieType.berryBlue.rawValue) smoothie is expected to have \\(expectedCount) ingredients: \\(expectedIngredients), however, there were \n\\(count) found.\"u003c/spanu003e)"
},
{
"title": "Asynchronous events",
"startTimeSeconds": 561,
"endTimeSeconds": 612,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eselectRecipeu003c/spanu003eu003cspan class=\"syntax-params\"u003e(smoothie: SmoothieType)u003c/spanu003eu003c/spanu003e u003cspan class=\"syntax-keyword\"u003ethrowsu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eRecipeu003c/spanu003e {\n element.buttons[smoothie.rawValue].tap()\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e app.recipe()\n}\n\nu003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003erecipeu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e u003cspan class=\"syntax-keyword\"u003ethrowsu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eRecipeu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e element = scrollViews[u003cspan class=\"syntax-string\"u003e\"Ingredients View\"u003c/spanu003e]\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e !element.waitForExistence(timeout: u003cspan class=\"syntax-number\"u003e5u003c/spanu003e) {\n u003cspan class=\"syntax-keyword\"u003ethrowu003c/spanu003e u003cspan class=\"syntax-type\"u003eFrutaErroru003c/spanu003e.elementDoesNotExist(\n u003cspan class=\"syntax-string\"u003e\"Ingredients View scroll view\"u003c/spanu003e)\n }\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-type\"u003eRecipeu003c/spanu003e(app: u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e, element: element)\n}"
},
{
"title": "Unwrapping optionals",
"startTimeSeconds": 619,
"endTimeSeconds": 631,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ecountFavoritesu003c/spanu003eu003cspan class=\"syntax-params\"u003e(favorites: [String]?)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eIntu003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e favs = favorites!\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e favs.u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e\n}"
},
{
"title": "Unwrapping optionals continued",
"startTimeSeconds": 656,
"endTimeSeconds": 713,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e favs = favorites {  }\nu003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e favs = favorites u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e { u003cspan class=\"syntax-comment\"u003e/* throw an error */u003c/spanu003e }\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e favs = favorites ?? []\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e favs = u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e u003cspan class=\"syntax-type\"u003eXCTUnwrapu003c/spanu003e(favorites, u003cspan class=\"syntax-string\"u003e\"favorites is nil, so there is nothing to count”)u003c/spanu003e"
},
{
"title": "Throw errors from shared code",
"startTimeSeconds": 739,
"endTimeSeconds": 778,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003everifyu003c/spanu003eu003cspan class=\"syntax-params\"u003e(ingredients: [String])u003c/spanu003eu003c/spanu003e u003cspan class=\"syntax-keyword\"u003ethrowsu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e u003cspan class=\"syntax-type\"u003eXCTContextu003c/spanu003e.runActivity(named: u003cspan class=\"syntax-string\"u003e\"Verifying \\(ingredients) exists in the Recipe screen.\"u003c/spanu003e)\n { verifyingRecipe u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e ingredient u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e ingredients {\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e !element.switches[ingredient].waitForExistence(timeout: u003cspan class=\"syntax-number\"u003e5u003c/spanu003e) {\n u003cspan class=\"syntax-keyword\"u003ethrowu003c/spanu003e u003cspan class=\"syntax-type\"u003eRecipeErroru003c/spanu003e.ingredientDoesNotExist(ingredient)\n }\n }\n }\n}\n\nu003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eenumu003c/spanu003e u003cspan class=\"syntax-title\"u003eRecipeErroru003c/spanu003e : u003cspan class=\"syntax-title\"u003eErroru003c/spanu003e, u003cspan class=\"syntax-title\"u003eCustomStringConvertibleu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e ingredientDoesNotExist(u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e)\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e description : u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eswitchu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .ingredientDoesNotExist(u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e ingredient):\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-string\"u003e\"\\(ingredient) does not exist in the Ingredients View.)\"u003c/spanu003e\n }\n }\n}"
},
{
"title": "Use XCTContext.runActivity()",
"startTimeSeconds": 821,
"endTimeSeconds": 841,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003everifyu003c/spanu003eu003cspan class=\"syntax-params\"u003e(ingredients: [String])u003c/spanu003eu003c/spanu003e u003cspan class=\"syntax-keyword\"u003ethrowsu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e u003cspan class=\"syntax-type\"u003eXCTContextu003c/spanu003e.runActivity(named: u003cspan class=\"syntax-string\"u003e\"Verifying \\(ingredients) exists in the Recipe screen.\"u003c/spanu003e)\n { verifyingRecipe u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e ingredient u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e ingredients {\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e !element.switches[ingredient].waitForExistence(timeout: u003cspan class=\"syntax-number\"u003e5u003c/spanu003e) {\n u003cspan class=\"syntax-keyword\"u003ethrowu003c/spanu003e u003cspan class=\"syntax-type\"u003eRecipeErroru003c/spanu003e.ingredientDoesNotExist(ingredient)\n }\n }\n }"
},
{
"title": "Add attachments to the result bundle",
"startTimeSeconds": 842,
"endTimeSeconds": 854,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003everifyu003c/spanu003eu003cspan class=\"syntax-params\"u003e(ingredients: [String])u003c/spanu003eu003c/spanu003e u003cspan class=\"syntax-keyword\"u003ethrowsu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e u003cspan class=\"syntax-type\"u003eXCTContextu003c/spanu003e.runActivity(named: u003cspan class=\"syntax-string\"u003e\"Verifying \\(ingredients) exists in the Recipe screen.\"u003c/spanu003e)\n { verifyingRecipe u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e ingredient u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e ingredients {\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e !element.switches[ingredient].waitForExistence(timeout: u003cspan class=\"syntax-number\"u003e5u003c/spanu003e) {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e attachment = u003cspan class=\"syntax-type\"u003eXCTAttachmentu003c/spanu003e(string: element.debugDescription)\n verifyingRecipe.add(attachment)\n u003cspan class=\"syntax-keyword\"u003ethrowu003c/spanu003e u003cspan class=\"syntax-type\"u003eRecipeErroru003c/spanu003e.ingredientDoesNotExist(ingredient)\n }\n }\n }"
},
{
"title": "Use XCTSkip",
"startTimeSeconds": 890,
"endTimeSeconds": 930,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e debuggingTests = u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003etestSelectSmoothieu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e u003cspan class=\"syntax-keyword\"u003ethrowsu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e u003cspan class=\"syntax-type\"u003eXCTSkipUnlessu003c/spanu003e(debuggingTests == u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e, u003cspan class=\"syntax-string\"u003e\"This test is not yet implemented.\"u003c/spanu003e)\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10091/2/B1C6A6C1-C50B-41C3-826B-AE16864B2245/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10091/2/B1C6A6C1-C50B-41C3-826B-AE16864B2245/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10091/2/B1C6A6C1-C50B-41C3-826B-AE16864B2245/transcripts/wwdc2020-10091-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10091/2/B1C6A6C1-C50B-41C3-826B-AE16864B2245/wwdc2020_10091_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10091/2/B1C6A6C1-C50B-41C3-826B-AE16864B2245/wwdc2020_10091_sd.mp4",
"duration": 1075
},
"related": {
"activities": [
"wwdc2020-10142",
"wwdc2020-10164",
"wwdc2020-10220",
"wwdc2020-10221",
"wwdc2020-10687",
"wwdc2020-10746"
],
"resources": [
1207,
1206
]
}
},
{
"id": "wwdc2020-10045",
"staticContentId": 3508,
"eventContentId": 10045,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10045",
"description": "Diffable data sources dramatically simplify the work involved in managing and updating collection and table views to create dynamic and responsive experiences in your apps. Discover how you can use section snapshots to efficiently build lists and outline collection views for iOS and iPadOS and provide support for implementing the sidebar in an iPad app. We’ll also show you how to simplify cell reordering using UICollectionViewDiffableDataSource to help you streamline your code and build app interfaces more quickly.\r\n\r\nThis session builds on 2019’s “Advances in UI Data Sources,” which you may want to check out first.",
"title": "Advances in diffable data sources",
"originalPublishingDate": "2020-06-23T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS"
],
"keywords": [
"uicollectionview",
"uitableview"
],
"topicIds": [
22
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "NSDiffableDataSourceSectionSnapshot",
"startTimeSeconds": 204,
"endTimeSeconds": 260,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// NSDiffableDataSourceSectionSnapshotu003c/spanu003e\n\nu003cspan class=\"syntax-meta\"u003e@availableu003c/spanu003e(iOS u003cspan class=\"syntax-number\"u003e14.0u003c/spanu003e, tvOS u003cspan class=\"syntax-number\"u003e14.0u003c/spanu003e, *)\nu003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eNSDiffableDataSourceSectionSnapshotu003c/spanu003eu0026lt;u003cspan class=\"syntax-title\"u003eItemIdentifierTypeu003c/spanu003eu0026gt; u003cspan class=\"syntax-title\"u003ewhereu003c/spanu003e u003cspan class=\"syntax-title\"u003eItemIdentifierTypeu003c/spanu003e : u003cspan class=\"syntax-title\"u003eHashableu003c/spanu003e u003c/spanu003e{\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003einitu003c/spanu003e()\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003einitu003c/spanu003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e snapshot: u003cspan class=\"syntax-type\"u003eNSDiffableDataSourceSectionSnapshotu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eItemIdentifierTypeu003c/spanu003eu0026gt;)\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003emutatingu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eappendu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e items: [ItemIdentifierType], to parent: ItemIdentifierType? = u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e)u003c/spanu003eu003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003emutatingu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003einsertu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e items: [ItemIdentifierType], before item: ItemIdentifierType)u003c/spanu003eu003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003emutatingu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003einsertu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e items: [ItemIdentifierType], after item: ItemIdentifierType)u003c/spanu003eu003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003emutatingu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003edeleteu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e items: [ItemIdentifierType])u003c/spanu003eu003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003emutatingu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003edeleteAllu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003emutatingu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eexpandu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e items: [ItemIdentifierType])u003c/spanu003eu003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003emutatingu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ecollapseu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e items: [ItemIdentifierType])u003c/spanu003eu003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003emutatingu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ereplaceu003c/spanu003eu003cspan class=\"syntax-params\"u003e(childrenOf parent: ItemIdentifierType, using snapshot: NSDiffableDataSourceSectionSnapshotu0026lt;ItemIdentifierTypeu0026gt;)u003c/spanu003eu003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003emutatingu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003einsertu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e snapshot: NSDiffableDataSourceSectionSnapshotu0026lt;ItemIdentifierTypeu0026gt;, before item: u003cspan class=\"syntax-params\"u003e(ItemIdentifierType)u003c/spanu003eu003c/spanu003eu003c/spanu003e)\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003emutatingu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003einsertu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e snapshot: NSDiffableDataSourceSectionSnapshotu0026lt;ItemIdentifierTypeu0026gt;, after item: u003cspan class=\"syntax-params\"u003e(ItemIdentifierType)u003c/spanu003eu003c/spanu003eu003c/spanu003e)\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eisExpandedu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e item: ItemIdentifierType)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eisVisibleu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e item: ItemIdentifierType)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003econtainsu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e item: ItemIdentifierType)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003elevelu003c/spanu003eu003cspan class=\"syntax-params\"u003e(of item: ItemIdentifierType)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eIntu003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eindexu003c/spanu003eu003cspan class=\"syntax-params\"u003e(of item: ItemIdentifierType)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eInt?u003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eparentu003c/spanu003eu003cspan class=\"syntax-params\"u003e(of child: ItemIdentifierType)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eItemIdentifierType?u003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003esnapshotu003c/spanu003eu003cspan class=\"syntax-params\"u003e(of parent: ItemIdentifierType, includingParent: Bool = u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eNSDiffableDataSourceSectionSnapshotu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eItemIdentifierTypeu003c/spanu003eu0026gt;\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e items: [u003cspan class=\"syntax-type\"u003eItemIdentifierTypeu003c/spanu003e] { u003cspan class=\"syntax-keyword\"u003egetu003c/spanu003e }\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e rootItems: [u003cspan class=\"syntax-type\"u003eItemIdentifierTypeu003c/spanu003e] { u003cspan class=\"syntax-keyword\"u003egetu003c/spanu003e }\n\n u003cspan class=\"syntax-keyword\"u003epublicu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e visibleItems: [u003cspan class=\"syntax-type\"u003eItemIdentifierTypeu003c/spanu003e] { u003cspan class=\"syntax-keyword\"u003egetu003c/spanu003e }\n}"
},
{
"title": "UICollectionViewDiffableDataSource Additions for Section Snapshots",
"startTimeSeconds": 260,
"endTimeSeconds": 282,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// UICollectionViewDiffableDataSource additions for iOS 14u003c/spanu003e\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eextensionu003c/spanu003e u003cspan class=\"syntax-title\"u003eUICollectionViewDiffableDataSourceu003c/spanu003eu0026lt;u003cspan class=\"syntax-title\"u003eItemu003c/spanu003e, u003cspan class=\"syntax-title\"u003eSectionu003c/spanu003eu0026gt; u003c/spanu003e{\n\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eapplyu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e snapshot: NSDiffableDataSourceSectionSnapshotu0026lt;Itemu0026gt;, \n to section: Section, \n animatingDifferences: Bool = u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e, \n completion: u003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003eu003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e)? = u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e)\n\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003esnapshotu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e section: Section)u003c/spanu003eu003c/spanu003e -u0026gt; \n u003cspan class=\"syntax-type\"u003eNSDiffableDataSourceSectionSnapshotu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eItemu003c/spanu003eu0026gt;\n}"
},
{
"title": "Using Snapshots and Section Snapshots together",
"startTimeSeconds": 283,
"endTimeSeconds": 311,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Example of using snapshots and section snapshots togetheru003c/spanu003e\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eupdateu003c/spanu003eu003cspan class=\"syntax-params\"u003e(animated: Bool=u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e)u003c/spanu003eu003c/spanu003e {\n\n u003cspan class=\"syntax-comment\"u003e// Add our sections in a specific orderu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e sections: [u003cspan class=\"syntax-type\"u003eSectionu003c/spanu003e] = [.recent, .top, .suggested]\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e snapshot = u003cspan class=\"syntax-type\"u003eNSDiffableDataSourceSnapshotu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eSectionu003c/spanu003e, u003cspan class=\"syntax-type\"u003eItemu003c/spanu003eu0026gt;()\n snapshot.appendSections(sections)\n dataSource.apply(snapshot, animatingDifferences: animated)\n\n u003cspan class=\"syntax-comment\"u003e// update each section's data via section snapshots in the existing positionu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e section u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e sections {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e sectionItems = items(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: section)\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e sectionSnapshot = u003cspan class=\"syntax-type\"u003eNSDiffableDataSourceSectionSnapshotu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eItemu003c/spanu003eu0026gt;()\n sectionSnapshot.append(sectionItems)\n dataSource.apply(sectionSnapshot, to: section, animatingDifferences:animated)\n }\n}"
},
{
"title": "Creating hierarchical data with NSDiffableDataSourceSectionSnapshot",
"startTimeSeconds": 318,
"endTimeSeconds": 347,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Create hierarchical data for our Outlineu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e sectionSnapshot = ...\n\nsectionSnapshot.append([u003cspan class=\"syntax-string\"u003e\"Smileys\"u003c/spanu003e, u003cspan class=\"syntax-string\"u003e\"Nature\"u003c/spanu003e, \n u003cspan class=\"syntax-string\"u003e\"Food\"u003c/spanu003e, u003cspan class=\"syntax-string\"u003e\"Activities\"u003c/spanu003e,\n u003cspan class=\"syntax-string\"u003e\"Travel\"u003c/spanu003e, u003cspan class=\"syntax-string\"u003e\"Objects\"u003c/spanu003e, u003cspan class=\"syntax-string\"u003e\"Symbols\"u003c/spanu003e])\n\nsectionSnapshot.append([u003cspan class=\"syntax-string\"u003e\"🥃\"u003c/spanu003e, u003cspan class=\"syntax-string\"u003e\"🍎\"u003c/spanu003e, u003cspan class=\"syntax-string\"u003e\"🍑\"u003c/spanu003e], to: u003cspan class=\"syntax-string\"u003e\"Food\"u003c/spanu003e)"
},
{
"title": "Child Section Snapshots",
"startTimeSeconds": 361,
"endTimeSeconds": 370,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e childSnapshot = sectionSnapshot.snapshot(u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e: parent, includingParent: u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e)"
},
{
"title": "Section Snapshot Expand / Collapse API",
"startTimeSeconds": 371,
"endTimeSeconds": 402,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eNSDiffableDataSourceSectionSnapshotu003c/spanu003eu0026lt;u003cspan class=\"syntax-title\"u003eItemu003c/spanu003e: u003cspan class=\"syntax-title\"u003eHashableu003c/spanu003eu0026gt; u003c/spanu003e{\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eexpandu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e items: [Item])u003c/spanu003eu003c/spanu003e\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ecollapseu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e items: [Item])u003c/spanu003eu003c/spanu003e\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eisExpandedu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e item: Item)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e\n}"
},
{
"title": "Section Snapshot Handlers",
"startTimeSeconds": 441,
"endTimeSeconds": 492,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Section Snapshot Handlers: handling user interactions for expand / collapse state changesu003c/spanu003e\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eextensionu003c/spanu003e u003cspan class=\"syntax-title\"u003eUICollectionViewDiffableDataSourceu003c/spanu003e u003c/spanu003e{\n\n u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eSectionSnapshotHandlersu003c/spanu003eu0026lt;u003cspan class=\"syntax-title\"u003eItemu003c/spanu003eu0026gt; u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e shouldExpandItem: ((u003cspan class=\"syntax-type\"u003eItemu003c/spanu003e) -u0026gt; u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e)?\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e willExpandItem: ((u003cspan class=\"syntax-type\"u003eItemu003c/spanu003e) -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e)?\n\t\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e shouldCollapseItem: ((u003cspan class=\"syntax-type\"u003eItemu003c/spanu003e) -u0026gt; u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e)?\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e willCollapseItem: ((u003cspan class=\"syntax-type\"u003eItemu003c/spanu003e) -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e)?\n \n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e snapshotForExpandingParent: ((u003cspan class=\"syntax-type\"u003eItemu003c/spanu003e, u003cspan class=\"syntax-type\"u003eNSDiffableDataSourceSectionSnapshotu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eItemu003c/spanu003eu0026gt;) -u0026gt; u003cspan class=\"syntax-type\"u003eNSDiffableDataSourceSectionSnapshotu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eItemu003c/spanu003eu0026gt;)?\n }\n \n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e sectionSnapshotHandlers: u003cspan class=\"syntax-type\"u003eSectionSnapshotHandlersu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eItemu003c/spanu003eu0026gt;\n \n}"
},
{
"title": "Reordering Handlers",
"startTimeSeconds": 532,
"endTimeSeconds": 584,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Diffable Data Source Reordering Handlersu003c/spanu003e\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eextensionu003c/spanu003e u003cspan class=\"syntax-title\"u003eUICollectionViewDiffableDataSourceu003c/spanu003e u003c/spanu003e{\n\n u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eReorderingHandlersu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e canReorderItem: ((u003cspan class=\"syntax-type\"u003eItemu003c/spanu003e) -u0026gt; u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e)?\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e willReorder: ((u003cspan class=\"syntax-type\"u003eNSDiffableDataSourceTransactionu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eSectionu003c/spanu003e, u003cspan class=\"syntax-type\"u003eItemu003c/spanu003eu0026gt;) -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e)?\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e didReorder: ((u003cspan class=\"syntax-type\"u003eNSDiffableDataSourceTransactionu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eSectionu003c/spanu003e, u003cspan class=\"syntax-type\"u003eItemu003c/spanu003eu0026gt;) -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e)?\n }\n\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e reorderingHandlers: u003cspan class=\"syntax-type\"u003eReorderingHandlersu003c/spanu003e\n}"
},
{
"title": "Diffable Data Source Transactions",
"startTimeSeconds": 585,
"endTimeSeconds": 663,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// NSDiffableDataSourceTransactionu003c/spanu003e\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eNSDiffableDataSourceTransactionu003c/spanu003eu0026lt;u003cspan class=\"syntax-title\"u003eSectionu003c/spanu003e, u003cspan class=\"syntax-title\"u003eItemu003c/spanu003eu0026gt; u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e initialSnapshot: u003cspan class=\"syntax-type\"u003eNSDiffableDataSourceSnapshotu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eSectionu003c/spanu003e, u003cspan class=\"syntax-type\"u003eItemu003c/spanu003eu0026gt; { u003cspan class=\"syntax-keyword\"u003egetu003c/spanu003e }\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e finalSnapshot: u003cspan class=\"syntax-type\"u003eNSDiffableDataSourceSnapshotu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eSectionu003c/spanu003e, u003cspan class=\"syntax-type\"u003eItemu003c/spanu003eu0026gt; { u003cspan class=\"syntax-keyword\"u003egetu003c/spanu003e }\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e difference: u003cspan class=\"syntax-type\"u003eCollectionDifferenceu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eItemu003c/spanu003eu0026gt; { u003cspan class=\"syntax-keyword\"u003egetu003c/spanu003e }\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e sectionTransactions: [u003cspan class=\"syntax-type\"u003eNSDiffableDataSourceSectionTransactionu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eSectionu003c/spanu003e, u003cspan class=\"syntax-type\"u003eItemu003c/spanu003eu0026gt;] { u003cspan class=\"syntax-keyword\"u003egetu003c/spanu003e }\n}\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eNSDiffableDataSourceSectionTransactionu003c/spanu003eu0026lt;u003cspan class=\"syntax-title\"u003eSectionu003c/spanu003e, u003cspan class=\"syntax-title\"u003eItemu003c/spanu003eu0026gt; u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e sectionIdentifier: u003cspan class=\"syntax-type\"u003eSectionu003c/spanu003e { u003cspan class=\"syntax-keyword\"u003egetu003c/spanu003e }\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e initialSnapshot: u003cspan class=\"syntax-type\"u003eNSDiffableDataSourceSectionSnapshotu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eItemu003c/spanu003eu0026gt; { u003cspan class=\"syntax-keyword\"u003egetu003c/spanu003e }\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e finalSnapshot: u003cspan class=\"syntax-type\"u003eNSDiffableDataSourceSectionSnapshotu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eItemu003c/spanu003eu0026gt; { u003cspan class=\"syntax-keyword\"u003egetu003c/spanu003e }\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e difference: u003cspan class=\"syntax-type\"u003eCollectionDifferenceu003c/spanu003eu0026lt;u003cspan class=\"syntax-type\"u003eItemu003c/spanu003eu0026gt; { u003cspan class=\"syntax-keyword\"u003egetu003c/spanu003e }\n}"
},
{
"title": "Diffable Data Source Reordering Example",
"startTimeSeconds": 667,
"endTimeSeconds": 682,
"language": "swift",
"code": "dataSource.reorderingHandlers.didReorder = { [u003cspan class=\"syntax-keyword\"u003eweaku003c/spanu003e u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e] transaction u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e \n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e { u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e }\n\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e updateBackingStore = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.backingStore.applying(transaction.difference) {\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.backingStore = updatedBackingStore\n }\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10045/2/7473959D-7A47-4AC5-ACC1-1FFD5712F680/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10045/2/7473959D-7A47-4AC5-ACC1-1FFD5712F680/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10045/2/7473959D-7A47-4AC5-ACC1-1FFD5712F680/transcripts/wwdc2020-10045-transcripts.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10045/2/7473959D-7A47-4AC5-ACC1-1FFD5712F680/wwdc2020_10045_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10045/2/7473959D-7A47-4AC5-ACC1-1FFD5712F680/wwdc2020_10045_sd.mp4",
"duration": 715
},
"related": {
"activities": [
"wwdc2020-10026",
"wwdc2020-10027",
"wwdc2020-10907",
"wwdc2019-220"
],
"resources": [
1103,
1102,
530
]
}
},
{
"id": "wwdc2020-10144",
"staticContentId": 3810,
"eventContentId": 10144,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=ywv74y7m",
"description": "",
"title": "Apple silicon and the Mac",
"articleID": "AF67EBBF-03C2-44AC-9823-2E96F34ED340",
"articlePermalinkKey": "ywv74y7m",
"originalPublishingDate": "2020-06-22T00:00:33-07:00",
"publishingExpiryDate": "2025-06-22T01:17:32-07:00",
"platforms": [
"macOS"
],
"topicIds": [
],
"type": "Article",
"images": [
"square",
"wide"
],
"related": {
"activities": [
"wwdc2020-10685"
]
}
},
{
"id": "wwdc2020-10694",
"staticContentId": 3888,
"eventContentId": 10694,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10694",
"description": "Just one more day to go for WWDC20. We’ve got the best of the day for you right here — and a quick look at what’s coming on our final day of WWDC.",
"title": "Thursday@WWDC",
"originalPublishingDate": "2020-06-25T22:00:00-07:00",
"publishingExpiryDate": "2022-06-22T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"keywords": [
"daily",
"daily recap",
"highlights",
"highlights thursday",
"recap",
"wwdc",
"wwdc20",
"wwdc recap",
"wwdc thursday"
],
"topicIds": [
1
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10694/2/533334C1-E3D7-425A-B669-FE559A9285E3/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10694/2/533334C1-E3D7-425A-B669-FE559A9285E3/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10694/2/533334C1-E3D7-425A-B669-FE559A9285E3/transcripts/wwdc2020-10694-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10694/2/533334C1-E3D7-425A-B669-FE559A9285E3/wwdc2020_10694_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10694/2/533334C1-E3D7-425A-B669-FE559A9285E3/wwdc2020_10694_sd.mp4",
"duration": 72
},
"related": {
"activities": [
"wwdc2020-10031",
"wwdc2020-10033",
"wwdc2020-10056",
"wwdc2020-10060",
"wwdc2020-10061",
"wwdc2020-10099",
"wwdc2020-10100",
"wwdc2020-10207",
"wwdc2020-10225",
"wwdc2020-10601",
"wwdc2020-10640",
"wwdc2020-10648",
"wwdc2020-10654",
"wwdc2020-10664",
"wwdc2020-10691",
"wwdc2020-10692",
"wwdc2020-10693",
"wwdc2020-10695"
]
}
},
{
"id": "wwdc2020-10687",
"staticContentId": 3881,
"eventContentId": 10687,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10687",
"description": "Put your test failures to work: Learn how to triage and diagnose uncaught issues in your app using the latest testing APIs in Xcode. We’ll show you how to help ease your testing workflow and put failures into context to help you deliver the best quality product.\r\n\r\nFor more information on designing your tests to improve triaging, see “Write tests to fail.”\r\n\r\nAnd check out the latest improvements to Xcode’s testing workflow by watching “Get your test results faster”, “Handle interruptions and alerts in UI tests”, and “XCTSkip your tests.”",
"title": "Triage test failures with XCTIssue",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"keywords": [
"test",
"test failure",
"testing",
"xcode",
"xctest",
"xctissue"
],
"topicIds": [
38,
37,
36
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Implement a custom test assertion using XCTIssue",
"startTimeSeconds": 592,
"endTimeSeconds": 653,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eassertSomethingu003c/spanu003eu003cspan class=\"syntax-params\"u003e(about data: Data,\n file: StaticString = #filePath,\n line: UInt = #line)u003c/spanu003eu003c/spanu003e {\n\n u003cspan class=\"syntax-comment\"u003e// Call out to custom validation function.u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e !isValid(data) {\n\n u003cspan class=\"syntax-comment\"u003e// Create issue, declare with var for mutability.u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e issue = u003cspan class=\"syntax-type\"u003eXCTIssueu003c/spanu003e(type: .u003cspan class=\"syntax-built_in\"u003eassertionFailureu003c/spanu003e, compactDescription: u003cspan class=\"syntax-string\"u003e\"Invalid data\"u003c/spanu003e)\n\n u003cspan class=\"syntax-comment\"u003e// Attach the invalid data.u003c/spanu003e\n issue.add(u003cspan class=\"syntax-type\"u003eXCTAttachmentu003c/spanu003e(data: data))\n\n u003cspan class=\"syntax-comment\"u003e// Capture the call site location as the point of failure.u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e location = u003cspan class=\"syntax-type\"u003eXCTSourceCodeLocationu003c/spanu003e(filePath: file, lineNumber: line)\n issue.sourceCodeContext = u003cspan class=\"syntax-type\"u003eXCTSourceCodeContextu003c/spanu003e(location: location)\n\n u003cspan class=\"syntax-comment\"u003e// Record the issue.u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.record(issue)\n }\n }"
},
{
"title": "Override record(_ issue:) for observation",
"startTimeSeconds": 672,
"endTimeSeconds": 689,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003erecordu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e issue: XCTIssue)u003c/spanu003eu003c/spanu003e {\n \n u003cspan class=\"syntax-comment\"u003e// Observe, introspect, log, etc.:u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e shouldLog(issue) {\n u003cspan class=\"syntax-built_in\"u003eprintu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"I just observed an issue!\"u003c/spanu003e)\n }\n\n u003cspan class=\"syntax-comment\"u003e// Don't forget to call super!u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003esuperu003c/spanu003e.record(issue)\n}"
},
{
"title": "Override record(_ issue:) to suppress failures",
"startTimeSeconds": 690,
"endTimeSeconds": 699,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003erecordu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e issue: XCTIssue)u003c/spanu003eu003c/spanu003e {\n\n u003cspan class=\"syntax-comment\"u003e// If you don't want to record it, just return.u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e shouldSuppress(issue) {\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e\n }\n\n u003cspan class=\"syntax-comment\"u003e// Otherwise pass it to super.u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003esuperu003c/spanu003e.record(issue)\n}"
},
{
"title": "Override record(_ issue:) to add an attachment",
"startTimeSeconds": 699,
"endTimeSeconds": 715,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eoverrideu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003erecordu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e issue: XCTIssue)u003c/spanu003eu003c/spanu003e {\n \n u003cspan class=\"syntax-comment\"u003e// Redeclare using var to enable mutation.u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e issue = issue\n\n u003cspan class=\"syntax-comment\"u003e// Add a simple attachment.u003c/spanu003e\n issue.add(u003cspan class=\"syntax-type\"u003eXCTAttachmentu003c/spanu003e(string: u003cspan class=\"syntax-string\"u003e\"hello\"u003c/spanu003e))\n \n u003cspan class=\"syntax-comment\"u003e// Pass it to super.u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003esuperu003c/spanu003e.record(issue)\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10687/4/9416FDA9-FC21-48ED-BBCC-ABF5C5A9B0DA/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10687/4/9416FDA9-FC21-48ED-BBCC-ABF5C5A9B0DA/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10687/4/9416FDA9-FC21-48ED-BBCC-ABF5C5A9B0DA/transcripts/wwdc2020-10687-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10687/4/9416FDA9-FC21-48ED-BBCC-ABF5C5A9B0DA/wwdc2020_10687_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10687/4/9416FDA9-FC21-48ED-BBCC-ABF5C5A9B0DA/wwdc2020_10687_sd.mp4",
"duration": 758
},
"related": {
"activities": [
"wwdc2020-10077",
"wwdc2020-10091",
"wwdc2020-10164",
"wwdc2020-10220",
"wwdc2020-10221"
],
"resources": [
1335,
1334
]
}
},
{
"id": "wwdc2020-10642",
"staticContentId": 3439,
"eventContentId": 10642,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10642",
"description": "Bring stylized effects to your photos and videos with Style Transfer in Create ML. Discover how you can train models in minutes that make it easy to bring creative visual features to your app. Learn about the training process and the options you have for controlling the results. And we’ll explore the real-time performance of these models by demonstrating three of them simultaneously in ARKit.\r\n\r\nTo get the most out of this session, you should be familiar with Create ML. For an overview, watch “Introducing the Create ML App.”",
"title": "Build Image and Video Style Transfer models in Create ML",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS"
],
"keywords": [
"ai",
"core ml",
"create ml",
"neural network",
"photo",
"photo effects",
"style density",
"style strength",
"style transfer",
"video",
"video effects"
],
"topicIds": [
38,
16
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10642/5/64274BC5-1940-4124-8B2F-4E1B9378202A/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10642/5/64274BC5-1940-4124-8B2F-4E1B9378202A/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10642/4/9A4D6DB0-180A-4422-93A1-162EAAB9C152/transcripts/wwdc2020-10642-transcripts.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10642/5/64274BC5-1940-4124-8B2F-4E1B9378202A/wwdc2020_10642_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10642/5/64274BC5-1940-4124-8B2F-4E1B9378202A/wwdc2020_10642_sd.mp4",
"duration": 708
},
"related": {
"activities": [
"wwdc2020-10156",
"wwdc2020-10711",
"wwdc2020-10717",
"wwdc2020-10718",
"wwdc2020-10719",
"wwdc2019-430"
],
"resources": [
1033,
1032,
443
]
}
},
{
"id": "wwdc2020-10170",
"staticContentId": 3483,
"eventContentId": 10170,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10170",
"description": "Join us for an update on Swift. Discover the latest advancements in runtime performance, along with improvements to the developer experience that make your code faster to read, edit, and debug. Find out how to take advantage of new language features like multiple trailing closures. Learn about new libraries available in the SDK, and explore the growing number of APIs available as Swift Packages.",
"title": "What's new in Swift",
"originalPublishingDate": "2020-06-23T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"topicIds": [
36
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Swift on AWS Lambda",
"startTimeSeconds": 812,
"endTimeSeconds": 820,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e AWSLambdaRuntime\n\nu003cspan class=\"syntax-type\"u003eLambdau003c/spanu003e.run { (u003cspan class=\"syntax-number\"u003e_u003c/spanu003e, event: u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e, callback) u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n callback(.success(u003cspan class=\"syntax-string\"u003e\"Hello, \\(event)\"u003c/spanu003e))\n}"
},
{
"title": "@main",
"startTimeSeconds": 1268,
"endTimeSeconds": 1276,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Type-based program entry pointsu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e ArgumentParser\n\n@main\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eHellou003c/spanu003e: u003cspan class=\"syntax-title\"u003eParsableCommandu003c/spanu003e u003c/spanu003e{\n @u003cspan class=\"syntax-type\"u003eArgumentu003c/spanu003e(help: u003cspan class=\"syntax-string\"u003e\"The name to greet.\"u003c/spanu003e)\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e name: u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e\n\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003erunu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-built_in\"u003eprintu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Hello, \\(name)!\"u003c/spanu003e)\n }\n}"
},
{
"title": "Synthesized comparable conformance for enums",
"startTimeSeconds": 1430,
"endTimeSeconds": 1438,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Synthesized comparable conformance for enumsu003c/spanu003e\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003eenumu003c/spanu003e u003cspan class=\"syntax-title\"u003eMessageStatusu003c/spanu003e: u003cspan class=\"syntax-title\"u003eHashableu003c/spanu003e, u003cspan class=\"syntax-title\"u003eComparableu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e draft\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e saved\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e failedToSend\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e sent\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e delivered\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e read\n\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e wasSent: u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e u0026gt;= .sent\n }\n}"
},
{
"title": "Compress and archive a source directory using Apple Archive",
"startTimeSeconds": 1639,
"endTimeSeconds": 1656,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Apple Archiveu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e AppleArchive\n\nu003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e u003cspan class=\"syntax-type\"u003eArchiveByteStreamu003c/spanu003e.withFileStream(\n path: u003cspan class=\"syntax-string\"u003e\"/tmp/VacationPhotos.aar\"u003c/spanu003e,\n mode: .writeOnly,\n options: [.create, .truncate],\n permissions: [.ownerReadWrite, .groupRead, .otherRead]\n) { file u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// Receives raw bytes and writes compressed bytes to `file`u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e u003cspan class=\"syntax-type\"u003eArchiveByteStreamu003c/spanu003e.withCompressionStream(using: .lzfse, writingTo: file) { compressor u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// Receives archive entries, and writes bytes to `compressor`u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e u003cspan class=\"syntax-type\"u003eArchiveStreamu003c/spanu003e.withEncodeStream(writingTo: compressor) { encoder u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-comment\"u003e// Writes all entries from `src` to `encoder`u003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e encoder.writeDirectoryContents(archiveFrom: source, keySet: fieldKeySet)\n }\n }\n}"
},
{
"title": "OSLog support for String interpolations and formatting options",
"startTimeSeconds": 1714,
"endTimeSeconds": 1719,
"language": "swift",
"code": "logger.log(u003cspan class=\"syntax-string\"u003e\"\\(offerID, align: .left(columns: 10), privacy: .public)\"u003c/spanu003e)\nu003cspan class=\"syntax-comment\"u003e// Logs \"E1Z3F \"u003c/spanu003e\n\nlogger.log(u003cspan class=\"syntax-string\"u003e\"\\(seconds, format: .fixed(precision: 2)) seconds\"u003c/spanu003e)\nu003cspan class=\"syntax-comment\"u003e// Logs \"1.30 seconds\"u003c/spanu003e"
},
{
"title": "ArgumentParser Swift Package",
"startTimeSeconds": 1805,
"endTimeSeconds": 1838,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Swift ArgumentParseru003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e ArgumentParser\n\n@main\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eHellou003c/spanu003e: u003cspan class=\"syntax-title\"u003eParsableCommandu003c/spanu003e u003c/spanu003e{\n @u003cspan class=\"syntax-type\"u003eOptionu003c/spanu003e(name: .shortAndLong, help: u003cspan class=\"syntax-string\"u003e\"The number of times to say hello.\"u003c/spanu003e)\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e: u003cspan class=\"syntax-type\"u003eIntu003c/spanu003e = u003cspan class=\"syntax-number\"u003e1u003c/spanu003e\n\n @u003cspan class=\"syntax-type\"u003eArgumentu003c/spanu003e(help: u003cspan class=\"syntax-string\"u003e\"The name to greet.\"u003c/spanu003e)\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e name: u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e\n\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003erunu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e u003cspan class=\"syntax-number\"u003e_u003c/spanu003e u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e u003cspan class=\"syntax-number\"u003e1u003c/spanu003e...u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e {\n u003cspan class=\"syntax-built_in\"u003eprintu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Hello, \\(name)!\"u003c/spanu003e)\n }\n }\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10170/7/9782B095-447A-49C8-A7D2-BB3B006CA5E2/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10170/7/9782B095-447A-49C8-A7D2-BB3B006CA5E2/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10170/7/9782B095-447A-49C8-A7D2-BB3B006CA5E2/transcripts/wwdc2020-10170-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10170/7/9782B095-447A-49C8-A7D2-BB3B006CA5E2/wwdc2020_10170_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10170/7/9782B095-447A-49C8-A7D2-BB3B006CA5E2/wwdc2020_10170_sd.mp4",
"duration": 1939
},
"related": {
"activities": [
"wwdc2020-10041",
"wwdc2020-10147",
"wwdc2020-10168",
"wwdc2020-10169",
"wwdc2020-10217"
],
"resources": [
1081,
1080,
845,
844,
842,
784,
45
]
}
},
{
"id": "wwdc2020-10071",
"staticContentId": 3474,
"eventContentId": 10071,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10071",
"description": "Optimize your app for Siri and give people a more natural way to interact with the features of your app. We’ll compare the different Siri technologies and help you identify the right one for you and your needs, show you how to get started with building for conversational interactions, and explore best practices for making your integration truly excel.",
"title": "Evaluate and optimize voice interaction for your app",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"tvOS",
"watchOS"
],
"keywords": [
"conversational interaction",
"design",
"intents",
"shortcuts",
"siri",
"sirikit",
"voice"
],
"topicIds": [
21,
6,
3
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10071/2/07184404-5005-4A26-B469-960B8653ECC9/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10071/2/07184404-5005-4A26-B469-960B8653ECC9/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10071/2/07184404-5005-4A26-B469-960B8653ECC9/transcripts/wwdc2020-10071-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10071/2/07184404-5005-4A26-B469-960B8653ECC9/wwdc2020_10071_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10071/2/07184404-5005-4A26-B469-960B8653ECC9/wwdc2020_10071_sd.mp4",
"duration": 607
},
"related": {
"activities": [
"wwdc2020-10053",
"wwdc2020-10060",
"wwdc2020-10061",
"wwdc2020-10068",
"wwdc2020-10073",
"wwdc2020-10074",
"wwdc2020-10083",
"wwdc2020-10084",
"wwdc2020-10086",
"wwdc2020-10087",
"wwdc2020-10088",
"wwdc2020-10190",
"wwdc2020-10200",
"wwdc2020-10203",
"wwdc2020-10839",
"wwdc2020-10877",
"wwdc2020-10914",
"wwdc2020-10917",
"wwdc2020-10963"
],
"resources": [
1077,
1076
]
}
},
{
"id": "wwdc2020-10228",
"staticContentId": 3704,
"eventContentId": 10228,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10228",
"description": "Apple has added Low-Latency extensions to the HTTP Live Streaming protocol that combine the quality and scalability of HLS with a stream delay of two seconds or less. Learn about the most recent developments in LL-HLS and how it allows you to make your video delivery competitive with broadcast and improve social media integration.\r\n\r\nFor an overview of Low-Latency HLS, watch “Introducing Low-Latency HLS” from WWDC19.",
"title": "What's new in Low-Latency HLS",
"originalPublishingDate": "2020-06-23T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"topicIds": [
31,
28
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10228/7/9BBA826D-6117-4305-A587-78FEE220580B/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10228/7/9BBA826D-6117-4305-A587-78FEE220580B/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10228/6/1905D3B5-15A1-4972-805E-B11F413C9C73/transcripts/wwdc2020-10228-transcripts.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10228/7/9BBA826D-6117-4305-A587-78FEE220580B/wwdc2020_10228_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10228/7/9BBA826D-6117-4305-A587-78FEE220580B/wwdc2020_10228_sd.mp4",
"duration": 354
},
"related": {
"activities": [
"wwdc2020-10225",
"wwdc2020-10229",
"wwdc2020-10230",
"wwdc2020-10231",
"wwdc2020-10847",
"wwdc2020-10851"
],
"resources": [
1253,
1252
]
}
},
{
"id": "wwdc2020-10200",
"staticContentId": 3695,
"eventContentId": 10200,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10200",
"description": "Understand what motivates people to use your app — and how you can use system intelligence to help them and achieve your own goals as a developer. We'll take a look at a typical person's journey to better understand how an app can become a key part of their routine — and why some apps just don't stick. Learn how you can provide the right kind of value at the right time to help them in their everyday tasks, and how your app and the system can evolve alongside them.",
"title": "Design for intelligence: Meet people where they are",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"keywords": [
"conversational interaction",
"extensions",
"intelligence",
"intelligence system experience",
"intents",
"intentsui",
"shortcuts",
"shortcuts app",
"siri",
"sirikit",
"system intelligence",
"voice",
"widgetkit",
"widgets"
],
"topicIds": [
39,
40,
21,
13,
6,
3
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10200/4/575ED5AA-73D9-48C4-904C-CC97FDE94A36/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10200/4/575ED5AA-73D9-48C4-904C-CC97FDE94A36/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10200/4/575ED5AA-73D9-48C4-904C-CC97FDE94A36/transcripts/wwdc2020-10200-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10200/4/575ED5AA-73D9-48C4-904C-CC97FDE94A36/wwdc2020_10200_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10200/4/575ED5AA-73D9-48C4-904C-CC97FDE94A36/wwdc2020_10200_sd.mp4",
"duration": 353
},
"related": {
"activities": [
"wwdc2020-10053",
"wwdc2020-10060",
"wwdc2020-10061",
"wwdc2020-10068",
"wwdc2020-10069",
"wwdc2020-10071",
"wwdc2020-10073",
"wwdc2020-10074",
"wwdc2020-10083",
"wwdc2020-10084",
"wwdc2020-10086",
"wwdc2020-10087",
"wwdc2020-10088",
"wwdc2020-10190",
"wwdc2020-10194",
"wwdc2020-10197",
"wwdc2020-10839",
"wwdc2020-10877",
"wwdc2020-10878",
"wwdc2020-10879",
"wwdc2020-10914",
"wwdc2020-10917",
"wwdc2020-10918",
"wwdc2020-10963",
"wwdc2020-10980"
],
"resources": [
1249,
1248
]
}
},
{
"id": "wwdc2020-20021",
"staticContentId": 4609,
"eventContentId": 20021,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/news/?id=gclaxoae",
"description": "",
"title": "Best of WWDC20",
"articleID": "45D3118A-D056-43C9-AA6F-3C2147A3E520",
"articlePermalinkKey": "gclaxoae",
"originalPublishingDate": "2020-06-26T18:15:04-07:00",
"publishingExpiryDate": "2025-06-26T19:06:14-07:00",
"topicIds": [
],
"type": "Article",
"images": [
"square",
"wide"
]
},
{
"id": "wwdc2020-10189",
"staticContentId": 3470,
"eventContentId": 10189,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10189",
"description": "It's more important than ever to consider vulnerabilities and potential threats and recognize where you should apply safeguards in your app. Understand how to identify potential risks through threat modeling and how to avoid common anti-patterns. Learn coding techniques and how to take advantage of platform-supplied protections to help you mitigate risk and protect people while they're using your app.",
"title": "Secure your app: threat modeling and anti-patterns",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"keywords": [
"data",
"privacy",
"protection",
"security",
"trust"
],
"topicIds": [
19
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Path traversal",
"startTimeSeconds": 994,
"endTimeSeconds": 1017,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ehandleIncomingFileu003c/spanu003eu003cspan class=\"syntax-params\"u003e(u003cspan class=\"syntax-number\"u003e_u003c/spanu003e incomingResourceURL: URL, with name: String, from fromID: String)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e safeFileName = name.lastPathComponent, \n safeFileName.u003cspan class=\"syntax-built_in\"u003ecountu003c/spanu003e u0026gt; u003cspan class=\"syntax-number\"u003e0u003c/spanu003e,\n safeFileName != u003cspan class=\"syntax-string\"u003e\"..\"u003c/spanu003e, safeFileName != u003cspan class=\"syntax-string\"u003e\".\"u003c/spanu003e u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e { u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e }\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e destinationFileURL = u003cspan class=\"syntax-type\"u003eURLu003c/spanu003e(fileURLWithPath: u003cspan class=\"syntax-type\"u003eNSTemporaryDirectoryu003c/spanu003e())\n .appendingPathComponent(safeFileName)\n\n u003cspan class=\"syntax-comment\"u003e// Copy the file into a temporary directoryu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003etryu003c/spanu003e! u003cspan class=\"syntax-type\"u003eFileManageru003c/spanu003e.u003cspan class=\"syntax-keyword\"u003edefaultu003c/spanu003e.copyItem(at: incomingResourceURL, to: destinationFileURL)\n\n}"
},
{
"title": "State management",
"startTimeSeconds": 1346,
"endTimeSeconds": 1357,
"language": "swift",
"code": "u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ehandleSessionInviteAcceptedu003c/spanu003eu003cspan class=\"syntax-params\"u003e(with message: RemoteMessage, from fromID: String)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e session = sessionsByIdentifier[message.sessionIdentifier],\n session.state == .inviting,\n session.invitedFromIdentifiers.u003cspan class=\"syntax-built_in\"u003econtainsu003c/spanu003e(fromID) u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e { u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e }\n\n session.state = .connected\n session.setupSocket(to: fromID) { socket u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n cameraController.send(to: socket)\n }\n}"
},
{
"title": "Safe dynamic allowedClasses",
"startTimeSeconds": 1856,
"endTimeSeconds": 1864,
"language": "objectivec",
"code": "u003cspan class=\"syntax-built_in\"u003eNSSetu003c/spanu003e *classesWhichConformToProtocol(Protocol *protocol) {\n u003cspan class=\"syntax-built_in\"u003eNSMutableSetu003c/spanu003e *conformingClasses = [u003cspan class=\"syntax-built_in\"u003eNSMutableSetu003c/spanu003e set];\n \n u003cspan class=\"syntax-keyword\"u003eunsignedu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eintu003c/spanu003e classesCount = u003cspan class=\"syntax-number\"u003e0u003c/spanu003e;\n Class *classes = objc_copyClassList(u0026amp;classesCount);\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e (classes != u003cspan class=\"syntax-literal\"u003eNULLu003c/spanu003e) {\n u003cspan class=\"syntax-keyword\"u003eforu003c/spanu003e (u003cspan class=\"syntax-keyword\"u003eunsignedu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eintu003c/spanu003e i = u003cspan class=\"syntax-number\"u003e0u003c/spanu003e; i u0026lt; classesCount; i++) {\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e (class_conformsToProtocol(classes[i], protocol)) {\n [conformingClasses addObject: classes[i]];\n }\n }\n free(classes);\n }\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e conformingClasses;\n}"
},
{
"title": "Buffer overflows",
"startTimeSeconds": 2063,
"endTimeSeconds": 2085,
"language": "objectivec",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003e@implementationu003c/spanu003eu003c/spanu003e\n- (u003cspan class=\"syntax-built_in\"u003eBOOLu003c/spanu003e)unpackTeaClubRecord:(CKRecord *)record {\n ...\n u003cspan class=\"syntax-built_in\"u003eNSDatau003c/spanu003e *data = [record objectForKey:u003cspan class=\"syntax-string\"u003e@\"uuid\"u003c/spanu003e];\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e (data == u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e ||\n ![data isKindOfClass:[u003cspan class=\"syntax-built_in\"u003eNSDatau003c/spanu003e u003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e]] ||\n data.length != u003cspan class=\"syntax-keyword\"u003esizeofu003c/spanu003e(_uuid)) {\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003eNOu003c/spanu003e;\n }\n memcpy(u0026amp;_uuid, data.bytes, data.length);\n ..."
},
{
"title": "Integer overflows",
"startTimeSeconds": 2166,
"endTimeSeconds": 2179,
"language": "objectivec",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003e@implementationu003c/spanu003eu003c/spanu003e\n- (u003cspan class=\"syntax-built_in\"u003eBOOLu003c/spanu003e)unpackTeaClubRecord:(CKRecord *)record {\n ...\n u003cspan class=\"syntax-built_in\"u003eNSDatau003c/spanu003e *name = [record objectForKey:u003cspan class=\"syntax-string\"u003e@\"name\"u003c/spanu003e];\n int32_t count = [[record objectForKey:u003cspan class=\"syntax-string\"u003e@\"nameCount\"u003c/spanu003e] unsignedIntegerValue];\n int32_t byteCount = u003cspan class=\"syntax-number\"u003e0u003c/spanu003e;\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e (name == u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e ||\n ![name isKindOfClass:[u003cspan class=\"syntax-built_in\"u003eNSDatau003c/spanu003e u003cspan class=\"syntax-keyword\"u003eclassu003c/spanu003e]] ||\n os_mul_overflow(count, u003cspan class=\"syntax-keyword\"u003esizeofu003c/spanu003e(u003cspan class=\"syntax-keyword\"u003eunicharu003c/spanu003e), u0026amp;byteCount) ||\n name.length != byteCount) {\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003eNOu003c/spanu003e;\n }\n _name = [[u003cspan class=\"syntax-built_in\"u003eNSStringu003c/spanu003e alloc] initWithCharacters:name.bytes \n length:count];\n ..."
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10189/4/164A0FEB-D524-40E7-89C9-A40F22CAA89C/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10189/4/164A0FEB-D524-40E7-89C9-A40F22CAA89C/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10189/4/164A0FEB-D524-40E7-89C9-A40F22CAA89C/transcripts/wwdc2020-10189-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10189/4/164A0FEB-D524-40E7-89C9-A40F22CAA89C/wwdc2020_10189_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10189/4/164A0FEB-D524-40E7-89C9-A40F22CAA89C/wwdc2020_10189_sd.mp4",
"duration": 2289
},
"related": {
"activities": [
"wwdc2020-10638",
"wwdc2020-10676",
"wwdc2020-10778",
"wwdc2020-10779"
],
"resources": [
1069,
1068,
74
]
}
},
{
"id": "wwdc2020-10205",
"staticContentId": 3771,
"eventContentId": 10205,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10205",
"description": "Create iPhone and iPad apps that look great and help people move quickly and directly to the information they need. Discover how you can integrate menus into your app for quick access to actions and settings, and learn where and when you should use them in your app. We’ll also walk you through the new Date Picker and Color Picker controls, and show you how to integrate them into your app.",
"title": "Design with iOS pickers, menus and actions",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS"
],
"topicIds": [
22,
6,
3
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10205/6/3F1FA0B1-A578-47C9-A8C8-77126E57FDBF/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10205/6/3F1FA0B1-A578-47C9-A8C8-77126E57FDBF/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10205/6/3F1FA0B1-A578-47C9-A8C8-77126E57FDBF/transcripts/wwdc2020-10205-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10205/6/3F1FA0B1-A578-47C9-A8C8-77126E57FDBF/wwdc2020_10205_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10205/6/3F1FA0B1-A578-47C9-A8C8-77126E57FDBF/wwdc2020_10205_sd.mp4",
"duration": 894
},
"related": {
"activities": [
"wwdc2020-10052",
"wwdc2020-10056",
"wwdc2020-10143",
"wwdc2020-10206",
"wwdc2020-10739"
],
"resources": [
1289,
1288,
10
]
}
},
{
"id": "wwdc2020-10650",
"staticContentId": 3580,
"eventContentId": 10650,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10650",
"description": "Discover how Core Data can help you adopt the CloudKit public database in your app with as little as one line of code. Learn how to easily manage the flow of data through your app and in and out of CloudKit. We’ll show you how to combine the complementary power of Core Data and the CloudKit public database to allow people to access — and contribute to — data, such as high scores or application templates. \r\n\r\nTo familiarize yourself with the CloudKit Database, check out our “CKDatabase” documentation, and to learn more about CloudKit integration, read “Mirroring a Core Data Store with CloudKit.”",
"title": "Sync a Core Data store with the CloudKit public database",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS"
],
"keywords": [
"canmodifymanagedobjects",
"canupdaterecordformanageddata",
"cdmr",
"ckfetchrecordzonechangesoperation",
"ckqueryoperation",
"deleting objects in the public database",
"derived objects",
"import",
"nspersistentcloudkitcontaineroptions",
"persistent container",
"private database",
"public database",
"record modify",
"schema"
],
"topicIds": [
22,
11
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10650/4/C47E2A5A-4327-4EAC-A879-3B8FD7904A58/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10650/4/C47E2A5A-4327-4EAC-A879-3B8FD7904A58/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10650/2/B21DB53A-9E7B-4C1B-B3D8-BFDADF501AE0/transcripts/wwdc2020-10650-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10650/4/C47E2A5A-4327-4EAC-A879-3B8FD7904A58/wwdc2020_10650_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10650/4/C47E2A5A-4327-4EAC-A879-3B8FD7904A58/wwdc2020_10650_sd.mp4",
"duration": 1098
},
"related": {
"activities": [
"wwdc2020-10724",
"wwdc2020-10725",
"wwdc2020-10726",
"wwdc2020-10900",
"wwdc2020-10901",
"wwdc2019-202"
],
"resources": [
1171,
1170,
698,
694,
693
]
}
},
{
"id": "wwdc2020-10115",
"staticContentId": 3807,
"eventContentId": 10115,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10115",
"description": "Discover how to implement AutoFill in your app and help people enter their information into fields easily, privately, and securely. Learn how to help the system to give better suggestions that tailor to your app's functionality: offer smart location suggestions within a navigation app, for example, or provide a private way to input contact information into fields from the QuickType bar.\r\n\r\nIn macOS Big Sur, AutoFill has been extended beyond Safari, to apps. Learn about the small changes that you can make to take advantage of this feature and bring convenience, added security, and a frictionless experience to people using your macOS apps.\r\n\r\nFor more on the latest privacy improvements to our platforms, watch “Build trust through better privacy.”",
"title": "AutoFill everywhere",
"originalPublishingDate": "2020-06-26T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS"
],
"keywords": [
"auto",
"fill",
"password",
"text input"
],
"topicIds": [
22,
19
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Address AutoFill",
"startTimeSeconds": 126,
"endTimeSeconds": 152,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e streetAddressTextField = u003cspan class=\"syntax-type\"u003eUITextFieldu003c/spanu003e()\nsteetAddressTextField.textContentType = .fullStreetAddress \n\nu003cspan class=\"syntax-comment\"u003e//Other address granularity: u003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// .addressCity, .addressCityAndState, .addressState, .countryNameu003c/spanu003e\nu003cspan class=\"syntax-comment\"u003e// .postalCode, .streetAddressLine1, .streetAddressLine2, .sublocalityu003c/spanu003e"
},
{
"title": "Contact AutoFill",
"startTimeSeconds": 377,
"endTimeSeconds": 393,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// AutoFill contacts' email addressu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e emailTextField = u003cspan class=\"syntax-type\"u003eUITextFieldu003c/spanu003e()\nemailTextField.textContentType = .emailAddress \n\nu003cspan class=\"syntax-comment\"u003e// AutoFill contacts' phone numberu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e phoneTextField = u003cspan class=\"syntax-type\"u003eUITextFieldu003c/spanu003e()\nphoneTextField.textContentType = .telephoneNumber \n\nu003cspan class=\"syntax-comment\"u003e// AutoFill contacts' address u003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e streetAddressTextField = u003cspan class=\"syntax-type\"u003eUITextFieldu003c/spanu003e()\nsteetAddressTextField.textContentType = .fullStreetAddress"
},
{
"title": "Password AutoFill",
"startTimeSeconds": 455,
"endTimeSeconds": 479,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e userTextField = u003cspan class=\"syntax-type\"u003eUITextFieldu003c/spanu003e()\nuserTextField.textContentType = .username\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e passwordTextField = u003cspan class=\"syntax-type\"u003eUITextFieldu003c/spanu003e()\npasswordTextField.textContentType = .password"
},
{
"title": "Security Code AutoFill",
"startTimeSeconds": 480,
"endTimeSeconds": 486,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e securityCodeTextField = u003cspan class=\"syntax-type\"u003eUITextFieldu003c/spanu003e()\nsecurityCodeTextField.textContentType = .oneTimeCode"
},
{
"title": "Automatic Strong Passwords",
"startTimeSeconds": 510,
"endTimeSeconds": 534,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e userTextField = u003cspan class=\"syntax-type\"u003eUITextFieldu003c/spanu003e()\nuserTextField.textContentType = .username\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e newPasswordTextField = u003cspan class=\"syntax-type\"u003eUITextFieldu003c/spanu003e()\nnewPasswordTextField.textContentType = .newPassword"
},
{
"title": "Password and Security Codes AutoFill for AppKit based apps",
"startTimeSeconds": 560,
"endTimeSeconds": 575,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e usernameTextField = u003cspan class=\"syntax-type\"u003eNSTextFieldu003c/spanu003e()\nusernameTextField.contentType = .username\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e passwordField = u003cspan class=\"syntax-type\"u003eNSSecureTextFieldu003c/spanu003e()\npasswordField.contentType = .password\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e securityCodeTextField = u003cspan class=\"syntax-type\"u003eNSTextFieldu003c/spanu003e()\nsecurityCodeTextField.contentType = .oneTimeCode"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10115/8/FFE4310A-D8B3-4E53-8BBF-D799F4F858E5/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10115/8/FFE4310A-D8B3-4E53-8BBF-D799F4F858E5/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10115/8/FFE4310A-D8B3-4E53-8BBF-D799F4F858E5/transcripts/wwdc2020-10115-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10115/8/FFE4310A-D8B3-4E53-8BBF-D799F4F858E5/wwdc2020_10115_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10115/8/FFE4310A-D8B3-4E53-8BBF-D799F4F858E5/wwdc2020_10115_sd.mp4",
"duration": 613
},
"related": {
"activities": [
"wwdc2020-10173",
"wwdc2020-10676"
],
"resources": [
1309,
1308
]
}
},
{
"id": "wwdc2020-101",
"staticContentId": 3921,
"eventContentId": 101,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/101",
"description": "The Apple Worldwide Developers Conference kicks off with exciting reveals, inspiration, and new opportunities to continue creating the most innovative apps in the world. Join the worldwide developer community for an in-depth look at the future of Apple platforms, directly from Apple Park.",
"title": "Keynote",
"originalPublishingDate": "2020-06-22T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"topicIds": [
1
],
"type": "Special Event",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://p-events-delivery.akamaized.net/2605bdtgclbnfypwzfkzdsupvcyzhhbx/m3u8/hls_vod_mvp.m3u8",
"tvOShls": "https://p-events-delivery.akamaized.net/2605bdtgclbnfypwzfkzdsupvcyzhhbx/m3u8/hls_vod_mvp.m3u8",
"duration": 6531
},
"related": {
"activities": [
"wwdc2020-10691"
]
}
},
{
"id": "wwdc2020-10646",
"staticContentId": 3646,
"eventContentId": 10646,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10646",
"description": "The Web Inspector makes introspection and debugging simpler than ever. Discover how you can use debugger stepping, editing cookies, and overriding network loaded resources to provide you with powerful development capabilities and help you create faster, more efficient websites.",
"title": "What's new in Web Inspector",
"originalPublishingDate": "2020-06-26T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS"
],
"keywords": [
"ad click attribution",
"animation-name",
"animations",
"audio",
"blackbox",
"bootstrap script",
"breakpoints",
"callbacks",
"canvas",
"console",
"cookies",
"css",
"css animations",
"css transitions",
"debugger",
"debugging",
"dom",
"dom tree",
"evaluation",
"fetch",
"html",
"http",
"indexeddb",
"inspected",
"intelligent tracking prevention",
"interval",
"itp",
"javascript",
"jscontext",
"json",
"layers",
"local override",
"localstorage",
"media",
"microtasks",
"network tab",
"page",
"paints",
"pretty print",
"profiling",
"promise",
"queryholders",
"queryinstances",
"regexp",
"regular expression",
"requestanimationframe",
"resources tab",
"safari",
"safari technology preview",
"setinterval",
"settimeout",
"step",
"storage",
"timelines",
"transition-property",
"video",
"webkit",
"webpage",
"website",
"websocket",
"wkwebview",
"xhr",
"xml"
],
"topicIds": [
20
],
"type": "Video",
"images": [
"square",
"wide"
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10646/4/FE1E3CA4-5AE6-4715-86C9-01777316518A/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10646/4/FE1E3CA4-5AE6-4715-86C9-01777316518A/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10646/3/7B1A2716-4A62-471B-9863-78B9598EBE24/transcripts/wwdc2020-10646-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10646/4/FE1E3CA4-5AE6-4715-86C9-01777316518A/wwdc2020_10646_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10646/4/FE1E3CA4-5AE6-4715-86C9-01777316518A/wwdc2020_10646_sd.mp4",
"duration": 1689
},
"related": {
"activities": [
"wwdc2020-10188",
"wwdc2020-10663",
"wwdc2020-10665",
"wwdc2020-10740",
"wwdc2020-10743",
"wwdc2020-10744",
"wwdc2020-10836"
],
"resources": [
1215,
1214,
774,
772,
771
]
}
},
{
"id": "wwdc2020-10672",
"staticContentId": 3403,
"eventContentId": 10672,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10672",
"description": "The ClassKit framework helps you surface educational activities within your app to teachers through the Schoolwork app. Discover how to provide a richer assignment experience for students and teachers through enhanced metadata properties and progress reporting. We’ll also show you how the new ClassKit Catalog APIs decouple management of your content from that of your app and improve overall discoverability.",
"title": "What's new in ClassKit",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS"
],
"keywords": [
"classroom",
"education",
"educators",
"school",
"testing"
],
"topicIds": [
12
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Add Thumbnail and Summary to Quiz Context",
"startTimeSeconds": 385,
"endTimeSeconds": 426,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Create a context for quizu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e quizContext = u003cspan class=\"syntax-type\"u003eCLSContextu003c/spanu003e.u003cspan class=\"syntax-keyword\"u003einitu003c/spanu003e(type: u003cspan class=\"syntax-type\"u003eCLSContextTypeu003c/spanu003e.quiz, identifier: u003cspan class=\"syntax-string\"u003e\"science_Investigation_quiz\"u003c/spanu003e, title: u003cspan class=\"syntax-string\"u003e\"Measurements Quiz\"u003c/spanu003e)\n\nu003cspan class=\"syntax-comment\"u003e// Add a summary describing this contextu003c/spanu003e\nquizContext.summary = u003cspan class=\"syntax-string\"u003e\"A short quiz to test how much students know about scientific measurements and how to examine and analyze scientific data.\"u003c/spanu003e\n\nu003cspan class=\"syntax-comment\"u003e// Add a thumbnail for this context — ClassKit will downsize thumbnails to 330 x 330 px if neededu003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e bundle = u003cspan class=\"syntax-type\"u003eBundleu003c/spanu003e.main\nu003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e resourceURL = bundle.resourceURL {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e imageURL = resourceURL.appendingPathComponent(u003cspan class=\"syntax-string\"u003e\"measurements_quiz.jpg\"u003c/spanu003e)\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e thumbnail = thumbnailFromImage(atURL: imageURL) {\n quizContext.thumbnail = thumbnail\n }\n}"
},
{
"title": "thumbnailFromImage",
"startTimeSeconds": 412,
"endTimeSeconds": 474,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Create a thumbnail of maximum dimension 330 x 330 px from an image fileu003c/spanu003e\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ethumbnailFromImageu003c/spanu003eu003cspan class=\"syntax-params\"u003e(atURL: URL)u003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eCGImage?u003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e imageSource = u003cspan class=\"syntax-type\"u003eCGImageSourceCreateWithURLu003c/spanu003e(atURL u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e u003cspan class=\"syntax-type\"u003eCFURLu003c/spanu003e, u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e) {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e thumbnailOptions = [kCGImageSourceCreateThumbnailFromImageAlways u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e: u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e,\n kCGImageSourceThumbnailMaxPixelSize u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e u003cspan class=\"syntax-type\"u003eStringu003c/spanu003e: u003cspan class=\"syntax-number\"u003e330u003c/spanu003e]\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-type\"u003eCGImageSourceCreateThumbnailAtIndexu003c/spanu003e(\n imageSource, u003cspan class=\"syntax-number\"u003e0u003c/spanu003e, thumbnailOptions u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e u003cspan class=\"syntax-type\"u003eCFDictionaryu003c/spanu003e);\n }\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e\n}"
},
{
"title": "Add suggestedAge and suggestedCompletionTime",
"startTimeSeconds": 479,
"endTimeSeconds": 498,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Add suggested age range appropriate for the content — ages 9 to 11 yearsu003c/spanu003e\n\nquizContext.suggestedAge = u003cspan class=\"syntax-type\"u003eNSRangeu003c/spanu003e(u003cspan class=\"syntax-number\"u003e9u003c/spanu003e...u003cspan class=\"syntax-number\"u003e11u003c/spanu003e)\n\nu003cspan class=\"syntax-comment\"u003e// Add suggested time to complete this quiz — 15 to 20 minutesu003c/spanu003e\n\nquizContext.suggestedCompletionTime = u003cspan class=\"syntax-type\"u003eNSRangeu003c/spanu003e(u003cspan class=\"syntax-number\"u003e15u003c/spanu003e...u003cspan class=\"syntax-number\"u003e20u003c/spanu003e)"
},
{
"title": "Add progress reporting capabilities",
"startTimeSeconds": 495,
"endTimeSeconds": 584,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Add progress reporting capabilitiesu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e reportingPercentDetails = u003cspan class=\"syntax-string\"u003e\"Reports percentage of progress\"u003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e reportingCapabilityPercent = u003cspan class=\"syntax-type\"u003eCLSProgressReportingCapabilityu003c/spanu003e.u003cspan class=\"syntax-keyword\"u003einitu003c/spanu003e(\n kind: .percent,\n details: reportingPercentDetails)\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e reportingQuantityDetails = u003cspan class=\"syntax-string\"u003e\"Reports number of hints used\"u003c/spanu003e\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e reportingCapabilityQuantity = u003cspan class=\"syntax-type\"u003eCLSProgressReportingCapabilityu003c/spanu003e.u003cspan class=\"syntax-keyword\"u003einitu003c/spanu003e(\n kind: .quantity,\n details: reportingQuantityDetails)\n\nquizContext.addProgressReportingCapabilities([reportingCapabilityPercent,\n reportingCapabilityQuantity])"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10672/4/F7DFFF2A-0E82-4B7F-BE8A-7C92F5A2E21C/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10672/4/F7DFFF2A-0E82-4B7F-BE8A-7C92F5A2E21C/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10672/4/F7DFFF2A-0E82-4B7F-BE8A-7C92F5A2E21C/transcripts/wwdc2020-10672-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10672/4/F7DFFF2A-0E82-4B7F-BE8A-7C92F5A2E21C/wwdc2020_10672_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10672/4/F7DFFF2A-0E82-4B7F-BE8A-7C92F5A2E21C/wwdc2020_10672_sd.mp4",
"duration": 1488
},
"related": {
"activities": [
"wwdc2020-10658",
"wwdc2020-10753"
],
"resources": [
987,
986,
385
]
}
},
{
"id": "wwdc2020-10168",
"staticContentId": 3603,
"eventContentId": 10168,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10168",
"description": "Meet the latest generation of Swift unified logging APIs. Learn how to log events and errors in your app while preserving privacy. Take advantage of powerful yet readable options for formatting data — all without sacrificing performance. And we’ll show you how you can gather and process log messages to help you understand and debug unexpected behavior in your apps.",
"title": "Explore logging in Swift",
"originalPublishingDate": "2020-06-24T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"topicIds": [
36,
19
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Example illustrating how to add logging to your app in three simple steps",
"startTimeSeconds": 164,
"endTimeSeconds": 211,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Add logging to your app in three simple stepsu003c/spanu003e\n \nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e os\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e logger = u003cspan class=\"syntax-type\"u003eLoggeru003c/spanu003e(subsystem: u003cspan class=\"syntax-string\"u003e\"com.example.Fruta\"u003c/spanu003e, category: u003cspan class=\"syntax-string\"u003e\"giftcards\"u003c/spanu003e)\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ebeginTasku003c/spanu003eu003cspan class=\"syntax-params\"u003e(url: URL, handler: u003cspan class=\"syntax-params\"u003e(Data)u003c/spanu003eu003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e) {\n launchTask(with: url) {\n handler($u003cspan class=\"syntax-number\"u003e0u003c/spanu003e)\n }\n\n logger.log(u003cspan class=\"syntax-string\"u003e\"Started a task\"u003c/spanu003e)\n}"
},
{
"title": "An example code that logs a message with run-time data",
"startTimeSeconds": 212,
"endTimeSeconds": 249,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Add runtime data to the log messsage using string interpolationu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e os\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e logger = u003cspan class=\"syntax-type\"u003eLoggeru003c/spanu003e(subsystem: u003cspan class=\"syntax-string\"u003e\"com.example.Fruta\"u003c/spanu003e, category: u003cspan class=\"syntax-string\"u003e\"giftcards\"u003c/spanu003e)\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ebeginTasku003c/spanu003eu003cspan class=\"syntax-params\"u003e(url: URL, handler: u003cspan class=\"syntax-params\"u003e(Data)u003c/spanu003eu003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e) {\n launchTask(with: url) {\n handler($u003cspan class=\"syntax-number\"u003e0u003c/spanu003e)\n }\n logger.log(u003cspan class=\"syntax-string\"u003e\"Started a task \\(taskId)\"u003c/spanu003e)\n}"
},
{
"title": "Example illustrating why nonnumeric types are redacted in the logs by default",
"startTimeSeconds": 268,
"endTimeSeconds": 296,
"language": "swift",
"code": "logger.log(u003cspan class=\"syntax-string\"u003e\"Paid with bank account \\(accountNumber)\"u003c/spanu003e)"
},
{
"title": "Code that shows how to mark public data so that it is displayed in the logs",
"startTimeSeconds": 301,
"endTimeSeconds": 316,
"language": "swift",
"code": "logger.log(u003cspan class=\"syntax-string\"u003e\"Ordered smoothie \\(smoothieName, privacy: .public)\"u003c/spanu003e)"
},
{
"title": "Code shown during first demo",
"startTimeSeconds": 363,
"endTimeSeconds": 394,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e SwiftUI\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e os\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e logger = u003cspan class=\"syntax-type\"u003eLoggeru003c/spanu003e(subsystem: u003cspan class=\"syntax-string\"u003e\"com.example.Fruta\"u003c/spanu003e, category: u003cspan class=\"syntax-string\"u003e\"giftcards\"u003c/spanu003e)\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eGiftCardViewu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-comment\"u003e// Denotes whether there is an active task for loading gift cards.u003c/spanu003e\n @u003cspan class=\"syntax-type\"u003eStateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eprivateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e taskRunning: u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e = u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e\n \n u003cspan class=\"syntax-comment\"u003e// A UUID that uniquely identifies a task.u003c/spanu003e\n @u003cspan class=\"syntax-type\"u003eStateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eprivateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e currentTaskID: u003cspan class=\"syntax-type\"u003eUUIDu003c/spanu003e = u003cspan class=\"syntax-type\"u003eUUIDu003c/spanu003e()\n \n u003cspan class=\"syntax-comment\"u003e// An unrecoverable error seen during execution.u003c/spanu003e\n @u003cspan class=\"syntax-type\"u003eStateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eprivateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e error: u003cspan class=\"syntax-type\"u003eError?u003c/spanu003e = u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e\n\n u003cspan class=\"syntax-comment\"u003e// A model that stores information about gift cards.u003c/spanu003e\n @u003cspan class=\"syntax-type\"u003eObservedObjectu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e model: u003cspan class=\"syntax-type\"u003eGiftCardModelu003c/spanu003e\n \n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-comment\"u003e// Display a list of gifts which can be tapped on and scrolled through.u003c/spanu003e\n u003cspan class=\"syntax-type\"u003eGiftCardListu003c/spanu003e(model: model, taskRunning: $taskRunning, currentTaskID: $currentTaskID, error: $error, downloadAction: beginTask, stopAction: endTask)\n .navigationTitle(u003cspan class=\"syntax-string\"u003e\"Gift Cards\"u003c/spanu003e)\n }\n \n u003cspan class=\"syntax-comment\"u003e// Start a task to download gift cards from a server.u003c/spanu003e\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ebeginTasku003c/spanu003eu003cspan class=\"syntax-params\"u003e(serverURL: URL, cardDownloadHandler: @escaping u003cspan class=\"syntax-params\"u003e(Data)u003c/spanu003eu003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e) {\n logger.log(u003cspan class=\"syntax-string\"u003e\"Starting a new task for loading cards \\(currentTaskID, privacy: .public)\"u003c/spanu003e) \n launchTask(with: serverURL) {\n cardDownloadHandler($u003cspan class=\"syntax-number\"u003e0u003c/spanu003e)\n }\n }\n \n u003cspan class=\"syntax-comment\"u003e// Stop the currently running task for downloading cards from a server.u003c/spanu003e\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eendTasku003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e taskRunning u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n logger.fault(u003cspan class=\"syntax-string\"u003e\"Task \\(currentTaskID, privacy: .public) is not runinng, cannot be stopped!\"u003c/spanu003e)\n error = u003cspan class=\"syntax-type\"u003eTaskErroru003c/spanu003e.noActiveTask\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e\n }\n taskRunning = u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e\n logger.log(u003cspan class=\"syntax-string\"u003e\"Task \\(currentTaskID, privacy: .public) interrupted\"u003c/spanu003e)\n }\n \n u003cspan class=\"syntax-comment\"u003e// Start a URLSession dataTask with the given URL.u003c/spanu003e\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003elaunchTasku003c/spanu003eu003cspan class=\"syntax-params\"u003e(with url: URL, handler: @escaping u003cspan class=\"syntax-params\"u003e(Data)u003c/spanu003eu003c/spanu003eu003c/spanu003e -u0026gt; u003cspan class=\"syntax-type\"u003eVoidu003c/spanu003e) {\n u003cspan class=\"syntax-keyword\"u003eguardu003c/spanu003e error == u003cspan class=\"syntax-literal\"u003enilu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eelseu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003ereturnu003c/spanu003e\n }\n taskRunning = u003cspan class=\"syntax-literal\"u003etrueu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e task = u003cspan class=\"syntax-type\"u003eURLSessionu003c/spanu003e.shared.dataTask(with: url) {\n data, response, error u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e error = error {\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.error = u003cspan class=\"syntax-type\"u003eConnectionErroru003c/spanu003e.other(error)\n }\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e data = data {\n handler(data)\n }\n }\n task.resume()\n }\n\n}"
},
{
"title": "Illustration of how debug-level logging will not evaluate the code that constructs log message",
"startTimeSeconds": 711,
"endTimeSeconds": 735,
"language": "swift",
"code": "logger.debug(u003cspan class=\"syntax-string\"u003e\"\\(slowFunction(data))\"u003c/spanu003e)"
},
{
"title": "Code that shows how to display run-time data with a fixed width and how to set precision of a floating-point value using formatting options",
"startTimeSeconds": 778,
"endTimeSeconds": 900,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e SwiftUI\nu003cspan class=\"syntax-keyword\"u003eimportu003c/spanu003e os\n\nu003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e statisticsLogger = u003cspan class=\"syntax-type\"u003eLoggeru003c/spanu003e(subsystem: u003cspan class=\"syntax-string\"u003e\"com.example.Fruta\"u003c/spanu003e, category: u003cspan class=\"syntax-string\"u003e\"statistics\"u003c/spanu003e)\n\nu003cspan class=\"syntax-comment\"u003e// Log statistics about communication with a server.u003c/spanu003e\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003elogStatisticsu003c/spanu003eu003cspan class=\"syntax-params\"u003e(taskID: UUID, giftCardID: String, serverID: Int, seconds: Double)u003c/spanu003eu003c/spanu003e {\n statisticsLogger.log(u003cspan class=\"syntax-string\"u003e\"\\(taskID) \\(giftCardID, align: .left(columns: GiftCard.maxIDLength)) \\(serverID) \\(seconds, format: .fixed(precision: 2))\"u003c/spanu003e)\n}"
},
{
"title": "Example of formatting log messages",
"startTimeSeconds": 900,
"endTimeSeconds": 919,
"language": "swift",
"code": "logger.log(u003cspan class=\"syntax-string\"u003e\"\\(data, format: .hex, align: .right(columns: width))\"u003c/spanu003e)"
},
{
"title": "Example illustrating the use of a hash to redact private data, which ensures that identical data get the same hash",
"startTimeSeconds": 965,
"endTimeSeconds": 996,
"language": "swift",
"code": "logger.log(u003cspan class=\"syntax-string\"u003e\"Paid with bank account: \\(accountNumber, privacy: .private(mask: .hash))\"u003c/spanu003e)"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10168/6/0D041A0B-E4FC-4830-B955-576922C47E29/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10168/6/0D041A0B-E4FC-4830-B955-576922C47E29/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10168/6/0D041A0B-E4FC-4830-B955-576922C47E29/transcripts/wwdc2020-10168-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10168/6/0D041A0B-E4FC-4830-B955-576922C47E29/wwdc2020_10168_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10168/6/0D041A0B-E4FC-4830-B955-576922C47E29/wwdc2020_10168_sd.mp4",
"duration": 1043
},
"related": {
"activities": [
"wwdc2020-10170",
"wwdc2020-10693"
],
"resources": [
1197,
1196
]
}
},
{
"id": "wwdc2020-10042",
"staticContentId": 3789,
"eventContentId": 10042,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10042",
"description": "Add a new dimension to your tvOS app with SwiftUI. We’ll show you how to build layouts powered by SwiftUI and customize your interface with custom buttons, provide more functionality in your app with a context menu, check if views are focused, and manage default focus.\r\n\r\nTo get the most out of this session, you should be comfortable with SwiftUI. For a primer, watch “Introducing SwiftUI: Building Your First App” and “SwiftUI On All Devices.”",
"title": "Build SwiftUI apps for tvOS",
"originalPublishingDate": "2020-06-23T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"tvOS"
],
"keywords": [
"apple tv",
"apple tv 4k",
"apple tv app",
"focus",
"focus engine",
"lazy grids",
"swift",
"swift developer",
"swiftui",
"tv",
"tv dev",
"tv developer",
"tvos",
"tv swift",
"tv swiftui"
],
"topicIds": [
31,
22
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "CardButtonStyle",
"startTimeSeconds": 102,
"endTimeSeconds": 118,
"language": "swift",
"code": "u003cspan class=\"syntax-type\"u003eButtonu003c/spanu003e(albumLabel, action: playAlbum)\n .buttonStyle(u003cspan class=\"syntax-type\"u003eCardButtonStyleu003c/spanu003e())"
},
{
"title": "Custom Button Styles",
"startTimeSeconds": 144,
"endTimeSeconds": 165,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eMyNewButtonStyleu003c/spanu003e: u003cspan class=\"syntax-title\"u003eButtonStyleu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003emakeBodyu003c/spanu003eu003cspan class=\"syntax-params\"u003e(configuration: Configuration)u003c/spanu003eu003c/spanu003e -u0026gt; some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n configuration.label\n .background(configuration.isPressed ? … : …) u003cspan class=\"syntax-comment\"u003e// Custom stylingu003c/spanu003e\n }\n} \n\nu003cspan class=\"syntax-type\"u003eButtonu003c/spanu003e(albumLabel, action: playAlbum)\n .buttonStyle(u003cspan class=\"syntax-type\"u003eMyNewButtonStyleu003c/spanu003e())"
},
{
"title": "Context Menus",
"startTimeSeconds": 199,
"endTimeSeconds": 212,
"language": "swift",
"code": "u003cspan class=\"syntax-type\"u003eAlbumViewu003c/spanu003e()\n .contextMenu {\n u003cspan class=\"syntax-type\"u003eButtonu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Add to Favorites\"u003c/spanu003e, action: addAlbumToFavorites)\n u003cspan class=\"syntax-type\"u003eButtonu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"View Artist\"u003c/spanu003e, action: viewArtistPage)\n u003cspan class=\"syntax-type\"u003eButtonu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Discover Similar Albums\"u003c/spanu003e, action: viewSimilarAlbums)\n }"
},
{
"title": "isFocused Environment Variable",
"startTimeSeconds": 347,
"endTimeSeconds": 428,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eSongViewu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eButtonu003c/spanu003e(action: playSong) {\n u003cspan class=\"syntax-type\"u003eVStacku003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eImageu003c/spanu003e(albumArt)\n u003cspan class=\"syntax-type\"u003eDetailsViewu003c/spanu003e(...)\n }\n }.buttonStyle(u003cspan class=\"syntax-type\"u003eMyCustomButtonStyleu003c/spanu003e())\n }\n}\n\nu003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eDetailsViewu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n ...\n @u003cspan class=\"syntax-type\"u003eEnvironmentu003c/spanu003e(\\.isFocused) u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e isFocused: u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eVStacku003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(songName)\n u003cspan class=\"syntax-type\"u003eTextu003c/spanu003e(isFocused ? artistAndAlbum : artistName)\n }\n }\n}"
},
{
"title": "Login Screen (Default Focus)",
"startTimeSeconds": 522,
"endTimeSeconds": 531,
"language": "swift",
"code": "u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eVStacku003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eTextFieldu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Username\"u003c/spanu003e, text: $username)\n\n u003cspan class=\"syntax-type\"u003eSecureFieldu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Password\"u003c/spanu003e, text: $password)\n\n u003cspan class=\"syntax-type\"u003eButtonu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Log In\"u003c/spanu003e, action: logIn)\n\n }\n\n}"
},
{
"title": "Default Focus",
"startTimeSeconds": 531,
"endTimeSeconds": 624,
"language": "swift",
"code": "@u003cspan class=\"syntax-type\"u003eNamespaceu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eprivateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e namespace\n@u003cspan class=\"syntax-type\"u003eStateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eprivateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e areCredentialsFilled: u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e\n\nu003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eVStacku003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eTextFieldu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Username\"u003c/spanu003e, text: $username)\n .prefersDefaultFocus(!areCredentialsFilled, u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e: namespace) \n u003cspan class=\"syntax-type\"u003eSecureFieldu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Password\"u003c/spanu003e, text: $password)\n\n u003cspan class=\"syntax-type\"u003eButtonu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Log In\"u003c/spanu003e, action: logIn)\n .prefersDefaultFocus(areCredentialsFilled, u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e: namespace)\n }\n .focusScope(namespace)\n}"
},
{
"title": "Reset Focus",
"startTimeSeconds": 672,
"endTimeSeconds": 692,
"language": "swift",
"code": "@u003cspan class=\"syntax-type\"u003eNamespaceu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eprivateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e namespace\n@u003cspan class=\"syntax-type\"u003eStateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eprivateu003c/spanu003e u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e areCredentialsFilled: u003cspan class=\"syntax-type\"u003eBoolu003c/spanu003e\n@u003cspan class=\"syntax-type\"u003eEnvironmentu003c/spanu003e(\\.resetFocus) u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e resetFocus\n\nu003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eVStacku003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eTextFieldu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Username\"u003c/spanu003e, text: $username)\n .prefersDefaultFocus(!areCredentialsFilled, u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e: namespace) \n u003cspan class=\"syntax-type\"u003eSecureFieldu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Password\"u003c/spanu003e, text: $password)\n\n u003cspan class=\"syntax-type\"u003eButtonu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Log In\"u003c/spanu003e, action: logIn)\n .prefersDefaultFocus(areCredentialsFilled, u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e: namespace)\n\n u003cspan class=\"syntax-type\"u003eButtonu003c/spanu003e(u003cspan class=\"syntax-string\"u003e\"Clear\"u003c/spanu003e, action: { \n username = u003cspan class=\"syntax-string\"u003e\"\"u003c/spanu003e; password = u003cspan class=\"syntax-string\"u003e\"\"u003c/spanu003e\n areCredentialsFilled = u003cspan class=\"syntax-literal\"u003efalseu003c/spanu003e\n resetFocus(u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e: namespace)\n })\n }\n .focusScope(namespace)\n}"
},
{
"title": "Lazy Grids",
"startTimeSeconds": 765,
"endTimeSeconds": 820,
"language": "swift",
"code": "u003cspan class=\"syntax-class\"u003eu003cspan class=\"syntax-keyword\"u003estructu003c/spanu003e u003cspan class=\"syntax-title\"u003eShelfViewu003c/spanu003e: u003cspan class=\"syntax-title\"u003eViewu003c/spanu003e u003c/spanu003e{\n u003cspan class=\"syntax-keyword\"u003evaru003c/spanu003e body: some u003cspan class=\"syntax-type\"u003eViewu003c/spanu003e {\n u003cspan class=\"syntax-type\"u003eScrollViewu003c/spanu003e([.horizontal]) {\n u003cspan class=\"syntax-type\"u003eLazyHGridu003c/spanu003e(rows: [u003cspan class=\"syntax-type\"u003eGridItemu003c/spanu003e()]) {\n u003cspan class=\"syntax-type\"u003eForEachu003c/spanu003e(playlists, id: \\.u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e) { playlist u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e \n u003cspan class=\"syntax-type\"u003eButtonu003c/spanu003e(action: goToPlaylist) {\n u003cspan class=\"syntax-type\"u003eImageu003c/spanu003e(playlist.coverImage)\n .resizable()\n .frame(…)\n }\n .buttonStyle(u003cspan class=\"syntax-type\"u003eCardButtonStyleu003c/spanu003e())\n }\n }\n }\n }\n}"
}
],
"media": {
"hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10042/4/B38E5ED8-1188-4675-877A-272A47769177/master.m3u8",
"tvOShls": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10042/4/B38E5ED8-1188-4675-877A-272A47769177/master.m3u8",
"subtitles": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10042/4/B38E5ED8-1188-4675-877A-272A47769177/transcripts/wwdc2020-10042-transcripts-en.vtt",
"downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10042/4/B38E5ED8-1188-4675-877A-272A47769177/wwdc2020_10042_hd.mp4",
"downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2020/10042/4/B38E5ED8-1188-4675-877A-272A47769177/wwdc2020_10042_sd.mp4",
"duration": 870
},
"related": {
"activities": [
"wwdc2020-10041",
"wwdc2020-10854",
"wwdc2020-10855",
"wwdc2019-204",
"wwdc2019-240"
],
"resources": [
1297,
1296,
864,
863,
862,
861,
829,
614,
576,
571
]
}
},
{
"id": "wwdc2020-10173",
"staticContentId": 3723,
"eventContentId": 10173,
"eventId": "wwdc2020",
"webPermalink": "https://developer.apple.com/wwdc20/10173",
"description": "Sign in with Apple makes it easy for people to sign in to your apps and websites with the Apple ID they already have. Fully integrate Sign in with Apple into your app using secure requests, and by handling state changes and server notifications. We’ll also introduce new APIs that allow you to let existing users switch to Sign in with Apple quickly and easily.",
"title": "Get the most out of Sign in with Apple",
"originalPublishingDate": "2020-06-25T10:00:00-07:00",
"publishingExpiryDate": "2025-06-08T00:00:00-07:00",
"platforms": [
"iOS",
"macOS",
"tvOS",
"watchOS"
],
"keywords": [
"account",
"account security",
"sign in",
"sign in with apple"
],
"topicIds": [
20,
19,
11
],
"type": "Video",
"images": [
"square",
"wide"
],
"codeSnippets": [
{
"title": "Create an Authorization Request",
"startTimeSeconds": 122,
"endTimeSeconds": 237,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Configure request, setup delegates and perform authorization requestu003c/spanu003e\n\n u003cspan class=\"syntax-meta\"u003e@objcu003c/spanu003e u003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003ehandleAuthorizationButtonPressu003c/spanu003eu003cspan class=\"syntax-params\"u003e()u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e request = u003cspan class=\"syntax-type\"u003eASAuthorizationAppleIDProvideru003c/spanu003e().createRequest()\n request.requestedScopes = [.fullName, .email]\n \n request.nonce = myNonceString()\n request.state = myStateString()\n \n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e controller = u003cspan class=\"syntax-type\"u003eASAuthorizationControlleru003c/spanu003e(authorizationRequests: [request])\n \n controller.delegate = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e\n controller.presentationContextProvider = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e\n \n controller.performRequests()\n }"
},
{
"title": "Get a credential from an Authorization",
"startTimeSeconds": 337,
"endTimeSeconds": 364,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// ASAuthorizationControllerDelegateu003c/spanu003e\n\nu003cspan class=\"syntax-function\"u003eu003cspan class=\"syntax-keyword\"u003efuncu003c/spanu003e u003cspan class=\"syntax-title\"u003eauthorizationControlleru003c/spanu003eu003cspan class=\"syntax-params\"u003e(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization)u003c/spanu003eu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eifu003c/spanu003e u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e credential = authorization.credential u003cspan class=\"syntax-keyword\"u003easu003c/spanu003e? u003cspan class=\"syntax-type\"u003eASAuthorizationAppleIDCredentialu003c/spanu003e {\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e userIdentifier = credential.user\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e fullName = credential.fullName\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e email = credential.email\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e realUserStatus = credential.realUserStatus\n \n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e state = credential.state\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e identityToken = credential.identityToken\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e authorizationCode = credential.authorizationCode\n \n u003cspan class=\"syntax-comment\"u003e// Securely store the userIdentifier locallyu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.saveUserIdentifier(userIdentifier)\n \n u003cspan class=\"syntax-comment\"u003e// Create a session with your server and verify the informationu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e.createSession(identityToken: identityToken, authorizationCode: authorizationCode)\n }\n}"
},
{
"title": "Verify the state of a credential",
"startTimeSeconds": 531,
"endTimeSeconds": 621,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Getting a credential stateu003c/spanu003e\n \n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e provider = u003cspan class=\"syntax-type\"u003eASAuthorizationAppleIDProvideru003c/spanu003e()\n \n provider.getCredentialState(forUserID: getStoredUserIdentifier()) { \n (credentialState, error) u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eswitchu003c/spanu003e(credentialState) {\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .authorized:\n u003cspan class=\"syntax-comment\"u003e// Sign in with Apple credential Validu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .revoked:\n u003cspan class=\"syntax-comment\"u003e// Sign in with Apple credential Revoked, Sign outu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .notFound:\n u003cspan class=\"syntax-comment\"u003e// Credential was not found, fallback to login screenu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .transferred:\n u003cspan class=\"syntax-comment\"u003e// Application was recently transferred, refresh User Identifieru003c/spanu003e\n @unknown u003cspan class=\"syntax-keyword\"u003edefaultu003c/spanu003e:\n u003cspan class=\"syntax-keyword\"u003ebreaku003c/spanu003e\n }\n }"
},
{
"title": "Migrate a user identifier",
"startTimeSeconds": 660,
"endTimeSeconds": 690,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// Migrating a user identifieru003c/spanu003e\n\n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e request = u003cspan class=\"syntax-type\"u003eASAuthorizationAppleIDProvideru003c/spanu003e().createRequest()\n request.requestedScopes = [.fullName, .email]\n \n request.user = getStoredUserIdentifier()\n \n request.nonce = myNonceString()\n request.state = myStateString()\n \n u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e controller = u003cspan class=\"syntax-type\"u003eASAuthorizationControlleru003c/spanu003e(authorizationRequests: [request])\n \n controller.delegate = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e\n controller.presentationContextProvider = u003cspan class=\"syntax-keyword\"u003eselfu003c/spanu003e\n \n controller.performRequests()"
},
{
"title": "Create a Sign in with Apple button",
"startTimeSeconds": 834,
"endTimeSeconds": 882,
"language": "swift",
"code": "u003cspan class=\"syntax-comment\"u003e// SwiftUI example:u003c/spanu003e\n\nu003cspan class=\"syntax-type\"u003eSignInWithAppleButtonu003c/spanu003e(.signIn) {\n onRequest: { (request) u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n request.requestedScopes = [.fullName, .email]\n request.nonce = myNonceString()\n request.state = myStateString()\n }\n onCompletion: { (result) u003cspan class=\"syntax-keyword\"u003einu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003eswitchu003c/spanu003e result {\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .success(u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e authorization):\n u003cspan class=\"syntax-comment\"u003e// Handle Authorizationu003c/spanu003e\n u003cspan class=\"syntax-keyword\"u003ecaseu003c/spanu003e .failure(u003cspan class=\"syntax-keyword\"u003eletu003c/spanu003e error)\n u003cspan class=\"syntax-comment\"u003e// Handle Failureu003c/spanu003e\n }\n }\n}.signInWithAppleButtonStyle(.black)"
},
{
"title": "convertAccountToSignInWithAppleWithoutUserInteraction",
"startTimeSeconds": 1515,
"endTimeSeconds": 1579,
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment