2022 Swift
Visualize and optimize Swift concurrency
Learn how you can optimize your app with the Swift Concurrency template in Instruments. We’ll discuss common performance issues and show you how to use Instruments to find and resolve these problems. Learn how you can keep your UI responsive, maximize parallel performance, and analyze Swift concurrency activity within your app. To get the most out of this session, we recommend familiarity with Swift concurrency (including tasks and actors).
Watch at developer.apple.com ↗Code shown on screen · 3 snippets
CompressionState class
class CompressionState: ObservableObject {
var files: [FileStatus] = []
var logs: [String] = []
func update(url: URL, progress: Double) {
if let loc = files.firstIndex(where: {$0.url == url}) {
files[loc].progress = progress
}
}
func update(url: URL, uncompressedSize: Int) {
if let loc = files.firstIndex(where: {$0.url == url}) {
files[loc].uncompressedSize = uncompressedSize
}
}
func update(url: URL, compressedSize: Int) {
if let loc = files.firstIndex(where: {$0.url == url}) {
files[loc].compressedSize = compressedSize
}
}
func compressAllFiles() {
for file in files {
Task {
let compressedData = compressFile(url: file.url)
await save(compressedData, to: file.url)
}
}
}
func compressFile(url: URL) -> Data {
log(update: "Starting for \(url)")
let compressedData = CompressionUtils.compressDataInFile(at: url) { uncompressedSize in
update(url: url, uncompressedSize: uncompressedSize)
} progressNotification: { progress in
update(url: url, progress: progress)
log(update: "Progress for \(url): \(progress)")
} finalNotificaton: { compressedSize in
update(url: url, compressedSize: compressedSize)
}
log(update: "Ending for \(url)")
return compressedData
}
func log(update: String) {
logs.append(update)
} CompressionState class using ParallelCompressor actor
actor ParallelCompressor {
var logs: [String] = []
unowned let status: CompressionState
init(status: CompressionState) {
self.status = status
}
func compressFile(url: URL) -> Data {
log(update: "Starting for \(url)")
let compressedData = CompressionUtils.compressDataInFile(at: url) { uncompressedSize in
Task { in
status.update(url: url, uncompressedSize: uncompressedSize)
}
} progressNotification: { progress in
Task { in
status.update(url: url, progress: progress)
await log(update: "Progress for \(url): \(progress)")
}
} finalNotificaton: { compressedSize in
Task { in
status.update(url: url, compressedSize: compressedSize)
}
}
log(update: "Ending for \(url)")
return compressedData
}
func log(update: String) {
logs.append(update)
}
}
class CompressionState: ObservableObject {
var files: [FileStatus] = []
var compressor: ParallelCompressor!
init() {
self.compressor = ParallelCompressor(status: self)
}
func update(url: URL, progress: Double) {
if let loc = files.firstIndex(where: {$0.url == url}) {
files[loc].progress = progress
}
}
func update(url: URL, uncompressedSize: Int) {
if let loc = files.firstIndex(where: {$0.url == url}) {
files[loc].uncompressedSize = uncompressedSize
}
}
func update(url: URL, compressedSize: Int) {
if let loc = files.firstIndex(where: {$0.url == url}) {
files[loc].compressedSize = compressedSize
}
}
func compressAllFiles() {
for file in files {
Task {
let compressedData = await compressor.compressFile(url: file.url)
await save(compressedData, to: file.url)
}
}
}
} CompressionState class using ParallelCompressor with minimal actor-isolation and detached tasks
actor ParallelCompressor {
var logs: [String] = []
unowned let status: CompressionState
init(status: CompressionState) {
self.status = status
}
nonisolated func compressFile(url: URL) async -> Data {
await log(update: "Starting for \(url)")
let compressedData = CompressionUtils.compressDataInFile(at: url) { uncompressedSize in
Task { in
status.update(url: url, uncompressedSize: uncompressedSize)
}
} progressNotification: { progress in
Task { in
status.update(url: url, progress: progress)
await log(update: "Progress for \(url): \(progress)")
}
} finalNotificaton: { compressedSize in
Task { in
status.update(url: url, compressedSize: compressedSize)
}
}
await log(update: "Ending for \(url)")
return compressedData
}
func log(update: String) {
logs.append(update)
}
}
class CompressionState: ObservableObject {
var files: [FileStatus] = []
var compressor: ParallelCompressor!
init() {
self.compressor = ParallelCompressor(status: self)
}
func update(url: URL, progress: Double) {
if let loc = files.firstIndex(where: {$0.url == url}) {
files[loc].progress = progress
}
}
func update(url: URL, uncompressedSize: Int) {
if let loc = files.firstIndex(where: {$0.url == url}) {
files[loc].uncompressedSize = uncompressedSize
}
}
func update(url: URL, compressedSize: Int) {
if let loc = files.firstIndex(where: {$0.url == url}) {
files[loc].compressedSize = compressedSize
}
}
func compressAllFiles() {
for file in files {
Task.detached {
let compressedData = await self.compressor.compressFile(url: file.url)
await save(compressedData, to: file.url)
}
}
}
} Resources
Related sessions
-
24 min -
43 min -
24 min -
17 min -
29 min -
38 min -
34 min -
29 min -
28 min -
1h 1m -
39 min