Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Backport AsyncImage

Backport AsyncImage

集まれSwift好き!Swift愛好会 vol.61 @ オンライン https://love-swift.connpass.com/event/218651/

Yutaro Muta

July 21, 2021
Tweet

More Decks by Yutaro Muta

Other Decks in Programming

Transcript

  1. SwiftUI.AsyncImage • > A view that asynchronously loads and displays

    an image. • Available on Xcode 13 struct AsyncImage<Content> where Content : View https://developer.apple.com/documentation/swiftui/asyncimage
  2. SwiftUI.AsyncImage AsyncImage(url: URL(string: “https://example.com/icon.png")) .frame(width: 200, height: 200) AsyncImage(url: URL(string:

    "https://example.com/icon.png")) { image in image.resizable() } placeholder: { ProgressView() } .frame(width: 50, height: 50)
  3. • ⚠ Availability • iOS 15.0+ Beta • macOS 12.0+

    Beta • Mac Catalyst 15.0+ Beta • tvOS 15.0+ Beta • watchOS 8.0+ Beta SwiftUI.AsyncImage
  4. yutailang0119/SBPAsyncImage • > Backport of SwiftUI.AsyncImage to iOS 14, macOS

    11, tvOS 14 and watchOS 7 and earlier. > SBPAsyncImage provides interface and behavior of AsyncImage to earlier OS. • Available on Xcode 12.5.1 struct BackportAsyncImage<Content> where Content : View typealias AsyncImage = BackportAsyncImage https://github.com/yutailang0119/SBPAsyncImage
  5. yutailang0119/SBPAsyncImage BackportAsyncImage(url: URL(string: “https://example.com/icon.png")) .frame(width: 200, height: 200) SBPAsyncImage.AsyncImage(url: URL(string:

    "https://example.com/icon.png")) { image in image.resizable() } placeholder: { ProgressView() } .frame(width: 50, height: 50)
  6. Availability • iOS 13.0+ • macOS 10.5+ • Mac Catalyst

    13.0+ • tvOS 13.0+ • watchOS 6.0+ yutailang0119/SBPAsyncImage
  7. Availability • iOS 13.0+ • macOS 10.5+ • Mac Catalyst

    13.0+ • tvOS 13.0+ • watchOS 6.0+ yutailang0119/SBPAsyncImage ✅ Cover all SwiftUI platforms
  8. yutailang0119/SBPAsyncImage • ⚠ SwiftUI.AsyncImage Λ׬શʹτϨʔεͰ͖ͯ͸͍ͳ͍ • ྫ͑͹ɺ௨৴ͷΩϟϯηϧ • SwiftUI.AsyncImage ͸

    task(_:) Ͱ௨৴Λ։͍࢝ͯͦ͠͏ • ⚠ macOS ͰScaleʹରԠͰ͖͍ͯͳ͍ • https://github.com/yutailang0119/SBPAsyncImage/issues/8 • Welcome Pull Request 🥴
  9. • https://github.com/yutailang0119/SBPAsyncImage/pull/5 Ҏલ͸ɺҎԼͷ Α͏ͳ࢖͍ํΛ͢ΔͱɺϘλϯΛԡ͢౓ʹ௨৴͞Ε͍ͯͨ • ϘλϯΛԡ͢౓ʹɺҰ౓ը૾͕ۭʹͳΔ struct ContentView: View {

    @State var count: Int = 0 var body: some View { VStack { SBPAsyncImage.AsyncImage(url: URL(string: "https://example.com/icon.png")) Button { count += 1 } label: { Text("Count: \(count)") } } } } Case1: @ObservableObject ͸ඳըຖʹinit͞ΕΔ
  10. • @StateObject Λ࢖ͬͯղܾ • ⚠ Availability • iOS 14.0+ •

    macOS 11.0+ • Mac Catalyst 14.0+ • tvOS 14.0+ • watchOS 7.0+ https://developer.apple.com/documentation/swiftui/stateobject Case1: @ObservableObject ͸ඳըຖʹinit͞ΕΔ
  11. • @StateObject Λ࢖͑ͳ͍ҎલͷOSͰ͸ @ObservableObject ͱ @State Λ૊Έ߹ΘͤͯɺৼΔ෣͍Λ໛฿͢Δ • ͘Θ͘͠͸ `iOS

    13Ͱ΋StateObject͕࢖͍͍ͨʂ` • https://kouki.hatenadiary.com/entry/2021/06/22/130000 Case1: @ObservableObject ͸ඳըຖʹinit͞ΕΔ
  12. • StateObject.init(wrappedValue:) • > You don’t call this initializer directly.

    Instead, declare a property with the @StateObject attribute in a View, App, or Scene, and provide an initial value: • initΛ௚઀࣮ߦ͢ΔͱɺSwiftUIͷϝϞϦ؅ཧ΍ @autoclosure ͷ࠷దԽ͕ ޮ͔ͳ͘ͳΔ https://developer.apple.com/documentation/swiftui/stateobject/init(wrappedvalue:) Case2: StateObject Λ௚઀initͯ͠͸͍͚ͳ͍ init(wrappedValue thunk: @autoclosure @escaping () -> ObjectType)
  13. • https://github.com/yutailang0119/SBPAsyncImage/pull/14 Ҏલ͸ɺҎԼ ͷΑ͏ʹStateObjectΛ௚઀init͍ͯͨ͠ @available(iOS 14.0, macOS 11.0, tvOS 14.0,

    watchOS 7.0, *) private struct ContentBody<Content: View>: View { @StateObject private var viewModel: ViewModel private let content: (AsyncImagePhase) -> Content init(viewModel: ViewModel, @ViewBuilder content: @escaping (AsyncImagePhase) -> Content) { self._viewModel = .init(wrappedValue: viewModel) self.content = content } } Case2: StateObject Λ௚઀initͯ͠͸͍͚ͳ͍
  14. • @StateObject ͷinit͸Viewʹ೚ͤͯɺStateObject͕ߦ͍͍ͨॲཧ͸ɺ onAppear(perform:) ʹҠಈ • ͘Θ͘͠͸ `Explanation behind the

    error? “Accessing StateObject’s object without being installed on a View. This will create a new instance each time.”` • https://forums.swift.org/t/explanation-behind-the-error-accessing- stateobjects-object-without-being-installed-on-a-view-this-will- create-a-new-instance-each-time/40111 Case2: StateObject Λ௚઀initͯ͠͸͍͚ͳ͍
  15. @available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) private

    struct ContentBody<Content: View>: View { @StateObject private var viewModel = ViewModel() ... var body: some View { content(viewModel.phase) .onAppear { viewModel.download(url: url, scale: scale, transaction: transaction) } } } Case2: StateObject Λ௚઀initͯ͠͸͍͚ͳ͍
  16. Reference • https://developer.apple.com/documentation/swiftui/asyncimage • https://github.com/yutailang0119/SBPAsyncImage • https://developer.apple.com/documentation/combine/observableobject • https://developer.apple.com/documentation/swiftui/stateobject •

    https://kouki.hatenadiary.com/entry/2021/06/22/130000 • https://developer.apple.com/documentation/swiftui/stateobject/init(wrappedvalue:) • https://forums.swift.org/t/explanation-behind-the-error-accessing-stateobjects-object-without- being-installed-on-a-view-this-will-create-a-new-instance-each-time/40111