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

Refactor with using `available` and `deprecated`

417.72KI
December 22, 2022

Refactor with using `available` and `deprecated`

potatotips#80

417.72KI

December 22, 2022
Tweet

More Decks by 417.72KI

Other Decks in Programming

Transcript

  1. "CPVUNF struct Me { let name = "Takuhiro Muta" let

    aka = "417.72KI" let company = "(redacted)" let twitter = "417_72ki" let qiita = "417_72ki" let gitHub = "417-72KI" let products = [ "MockUserDefaults", "MultipartFormDataParser", "BuildConfig.swift", "SSGH" ] let contributing = [ "Danger-Swift", "octokit.swift", "etc..." ] }
  2. 'JOEBOE3FQMBDFJO1BDLBHF // A.swift func doSomesing() { // do something }

    // C.swift func doSomething(with foo: Foo = .init()) { // do something with `foo` } // B.swift func call() { doSomesing() } // D.swift func callWithFoo() { doSomething() }
  3. 'JOEBOE3FQMBDFJO1BDLBHF // A.swift func doSomething() { // do something }

    // C.swift func doSomething(with foo: Foo = .init()) { // do something with `foo` } // B.swift func call() { doSomething() } // D.swift func callWithFoo() { doSomething() } 😱
  4. BWBJMBCMFʹ͍ͭͯ ओͳΦϓγϣϯ w ܯࠂ w EFQSFDBUFEඇਪ঑ όʔδϣϯলུՄ  w ϏϧυΤϥʔ

    w PCTPMFUFEഇࢭ όʔδϣϯলུෆՄ  w VOBWBJMBCMFར༻ෆՄ όʔδϣϯࢦఆෆՄ
  5. "UUSJCVUFE4USJOH var attributedString: AttributedString { // ← 'AttributedString' is only

    available in iOS 15 or newer var str = AttributedString("Foo Bar Baz Qux Quux") if let range = str.range(of: "Bar") { str[range].foregroundColor = .red } if let range = str.range(of: "Baz") { str[range].font = .title } if let range = str.range(of: "Qux") { str[range].font = .footnote str[range].foregroundColor = .green } return str } var body: some View { VStack { Text(attributedString) // ← 'init(_:)' is only available in iOS 15.0 or newer } }
  6. "UUSJCVUFE4USJOH @available(iOS 15, *) var attributedString: AttributedString { var str

    = AttributedString("Foo Bar Baz Qux Quux") if let range = str.range(of: "Bar") { str[range].foregroundColor = .red } if let range = str.range(of: "Baz") { str[range].font = .title } if let range = str.range(of: "Qux") { str[range].font = .footnote str[range].foregroundColor = .green } return str } var body: some View { VStack { Text(attributedString) // ← 'init(_:)' is only available in iOS 15.0 or newer } }
  7. "UUSJCVUFE4USJOH var body: some View { VStack { if #available(iOS

    15, *) { Text(attributedString) } else { Text("Foo") + Text(" ") + Text("Bar") .foregroundColor(.red) + Text(" ") + Text("Baz") .font(.title) + Text(" ") + Text("Qux") .font(.footnote) .foregroundColor(.green) + Text(" ") + Text("Quux") } } } @available(iOS 15, *) var attributedString: AttributedString { var str = AttributedString("Foo Bar Baz Qux Quux") if let range = str.range(of: "Bar") { str[range].foregroundColor = .red } if let range = str.range(of: "Baz") { str[range].font = .title } if let range = str.range(of: "Qux") { str[range].font = .footnote str[range].foregroundColor = .green } return str }
  8. "UUSJCVUFE4USJOH var body: some View { VStack { if #available(iOS

    15, *) { Text(attributedString) } else { AttributedText { Text("Foo") Text(" ") Text("Bar") .foregroundColor(.red) Text(" ") Text("Baz") .font(.title) Text(" ") Text("Qux") .font(.footnote) .foregroundColor(.green) Text(" ") Text("Quux") } } } } struct AttributedText: View { typealias Body = Text var text: Text init(@Builder builder: () -> Text) { text = builder() } var body: Text { text } } extension AttributedText { @resultBuilder enum Builder { ɾɾɾ } }
  9. "UUSJCVUFE4USJOH ໿ଋ͞Εٕͨज़తෛ࠴Λ຤୅·Ͱ͓֮͑ͯͨ͘Ίʹ var body: some View { VStack { AttributedText

    { Text("Foo") Text(" ") Text("Bar") .foregroundColor(.red) Text(" ") Text("Baz") .font(.title) Text(" ") Text("Qux") .font(.footnote) .foregroundColor(.green) Text(" ") Text("Quux") } } } struct AttributedText: View { typealias Body = Text var text: Text init(@Builder builder: () -> Text) { text = builder() } var body: Text { text } } extension AttributedText { @resultBuilder enum Builder { ɾɾɾ } }
  10. "UUSJCVUFE4USJOH .JOJNVN%FQMPZNFOU5BSHFU͕ҎԼͷؒ͸ܯࠂ͕ग़ͳ͍ @available(iOS, deprecated: 15.0, obsoleted: 16.0, message: "Use `Text`

    with `AttributedString`") struct AttributedText: View { typealias Body = Text var text: Text init(@Builder builder: () -> Text) { text = builder() } var body: Text { text } } @available(iOS, deprecated: 15.0, obsoleted: 16.0, message: "Use `Text` with `AttributedString`") extension AttributedText { @resultBuilder enum Builder { ɾɾɾ } } var body: some View { VStack { AttributedText { Text("Foo") Text(" ") Text("Bar") .foregroundColor(.red) Text(" ") Text("Baz") .font(.title) Text(" ") Text("Qux") .font(.footnote) .foregroundColor(.green) Text(" ") Text("Quux") } } }
  11. "UUSJCVUFE4USJOH .JOJNVN%FQMPZNFOU5BSHFUΛʹͨ͠Βܯࠂ͕ग़Δ @available(iOS, deprecated: 15.0, obsoleted: 16.0, message: "Use `Text`

    with `AttributedString`") struct AttributedText: View { typealias Body = Text var text: Text init(@Builder builder: () -> Text) { text = builder() } var body: Text { text } } @available(iOS, deprecated: 15.0, obsoleted: 16.0, message: "Use `Text` with `AttributedString`") extension AttributedText { @resultBuilder enum Builder { ɾɾɾ } } var body: some View { VStack { AttributedText { // ← 'AttributedText' was deprecated in iOS 15.0: Use `Text` with `AttributedString` Text("Foo") Text(" ") Text("Bar") .foregroundColor(.red) Text(" ") Text("Baz") .font(.title) Text(" ") Text("Qux") .font(.footnote) .foregroundColor(.green) Text(" ") Text("Quux") } } }
  12. "UUSJCVUFE4USJOH .JOJNVN%FQMPZNFOU5BSHFUΛʹͨ͠ΒϏϧυΤϥʔʹ @available(iOS, deprecated: 15.0, obsoleted: 16.0, message: "Use `Text`

    with `AttributedString`") struct AttributedText: View { typealias Body = Text var text: Text init(@Builder builder: () -> Text) { text = builder() } var body: Text { text } } @available(iOS, deprecated: 15.0, obsoleted: 16.0, message: "Use `Text` with `AttributedString`") extension AttributedText { @resultBuilder enum Builder { ɾɾɾ } } var body: some View { VStack { AttributedText { // ← 'AttributedText' is unavailable in iOS: Use `Text` with `AttributedString` Text("Foo") Text(" ") Text("Bar") .foregroundColor(.red) Text(" ") Text("Baz") .font(.title) Text(" ") Text("Qux") .font(.footnote) .foregroundColor(.green) Text(" ") Text("Quux") } } }
  13. "UUSJCVUFE4USJOH JGBWBJMBCMF \^FMTF\^ͰׅΒΕΔͱܯࠂ͕ग़ͳ͍ var body: some View { VStack {

    if #available(iOS 15, *) { Text(attributedString) } else { AttributedText { Text("Foo") Text(" ") Text("Bar") .foregroundColor(.red) Text(" ") Text("Baz") .font(.title) Text(" ") Text("Qux") .font(.footnote) .foregroundColor(.green) Text(" ") Text("Quux") } } } } @available(iOS, deprecated: 15.0, obsoleted: 16.0, message: "Use `Text` with `AttributedString`") struct AttributedText: View { typealias Body = Text var text: Text init(@Builder builder: () -> Text) { text = builder() } var body: Text { text } } @available(iOS, deprecated: 15.0, obsoleted: 16.0, message: "Use `Text` with `AttributedString`") extension AttributedText { @resultBuilder enum Builder { ɾɾɾ } }
  14. var body: some View { VStack { if #available(iOS 15,

    *) { Text(attributedString) } else { AttributedText { // ← 'AttributedText' is unavailable in iOS: Use `Text` with `AttributedString` Text("Foo") Text(" ") Text("Bar") .foregroundColor(.red) Text(" ") Text("Baz") .font(.title) Text(" ") Text("Qux") .font(.footnote) .foregroundColor(.green) Text(" ") Text("Quux") } } } } "UUSJCVUFE4USJOH PCTPMFUFEʹ͢ΔͱΤϥʔʹͳΔ @available(iOS, obsoleted: 15.0, message: "Use `Text` with `AttributedString`") struct AttributedText: View { typealias Body = Text var text: Text init(@Builder builder: () -> Text) { text = builder() } var body: Text { text } } @available(iOS, obsoleted: 15.0, message: "Use `Text` with `AttributedString`") extension AttributedText { @resultBuilder enum Builder { ɾɾɾ } }
  15. QSFTFOUBUJPO%FUFOUT struct ContentView: View { @State private var isPresenting =

    false var body: some View { VStack { Button { isPresenting = true } label: { VStack { Image(systemName: "globe") .imageScale(.large) Text("Hello, world!") }.foregroundColor(.accentColor) .padding() } .sheet(isPresented: $isPresenting) { SheetView() .presentationDetents([.medium]) // ← 'presentationDetents' is only available in iOS 16.0 or newer } } } }
  16. QSFTFOUBUJPO%FUFOUT struct ContentView: View { @State private var isPresenting =

    false var body: some View { VStack { Button { isPresenting = true } label: { VStack { Image(systemName: "globe") .imageScale(.large) Text("Hello, world!") }.foregroundColor(.accentColor) .padding() } .sheet(isPresented: $isPresenting) { if #available(iOS 16.0, *) { SheetView() .presentationDetents([.medium]) } else { SheetView() } } } } }
  17. QSFTFOUBUJPO%FUFOUT GVODUJPOʹ੾Γग़͢ extension View { @ViewBuilder func halfSheetIfAble(height: CGFloat? =

    nil) -> some View { if #available(iOS 16.0, *) { if let height { presentationDetents([.height(height)]) } else { presentationDetents([.medium]) } } else { self } } } struct ContentView: View { @State private var isPresenting = false var body: some View { VStack { Button { isPresenting = true } label: { VStack { Image(systemName: "globe") .imageScale(.large) Text("Hello, world!") }.foregroundColor(.accentColor) .padding() } .sheet(isPresented: $isPresenting) { SheetView() .halfSheetIfAble() } } } }
  18. QSFTFOUBUJPO%FUFOUT struct ContentView: View { @State private var isPresenting =

    false var body: some View { VStack { Button { isPresenting = true } label: { VStack { Image(systemName: "globe") .imageScale(.large) Text("Hello, world!") }.foregroundColor(.accentColor) .padding() } .sheet(isPresented: $isPresenting) { SheetView() .halfSheetIfAble() } } } } @available(iOS, deprecated: 16, message: "Use `presentationDetents` directly.") extension View { @ViewBuilder func halfSheetIfAble(height: CGFloat? = nil) -> some View { if #available(iOS 16.0, *) { if let height { presentationDetents([.height(height)]) } else { presentationDetents([.medium]) } } else { self } } }
  19. QSFTFOUBUJPO%FUFOUT .JOJNVN%FQMPZNFOU5BSHFUΛʹ͢Δͱܯࠂ͕ग़Δ struct ContentView: View { @State private var isPresenting

    = false var body: some View { VStack { Button { isPresenting = true } label: { VStack { Image(systemName: "globe") .imageScale(.large) Text("Hello, world!") }.foregroundColor(.accentColor) .padding() } .sheet(isPresented: $isPresenting) { SheetView() .halfSheetIfAble() // ← 'halfSheetIfAble(height:)' was deprecated in iOS 16: Use `presentationDetents` directly. } } } } @available(iOS, deprecated: 16, message: "Use `presentationDetents` directly.") extension View { @ViewBuilder func halfSheetIfAble(height: CGFloat? = nil) -> some View { if #available(iOS 16.0, *) { if let height { presentationDetents([.height(height)]) } else { presentationDetents([.medium]) } } else { self } } }
  20. QSFTFOUBUJPO%FUFOUT ผղಉ໊ͷCBDLQPSUGVODUJPOΛ༻ҙ͢Δ struct ContentView: View { @State private var isPresenting

    = false var body: some View { VStack { Button { isPresenting = true } label: { VStack { Image(systemName: "globe") .imageScale(.large) Text("Hello, world!") }.foregroundColor(.accentColor) .padding() } .sheet(isPresented: $isPresenting) { SheetView() .presentationDetents([.medium]) } } } } @available(iOS, obsoleted: 16, message: "Use `presentationDetents` in SwiftUI directly.") extension View { @ViewBuilder func presentationDetents(_ detents: Set<PresentationDetent>) -> some View { if #available(iOS 16.0, *) { presentationDetents(Set(detents.map(\.detent))) } else { self } } } /// Backporting for `SwiftUI.PresentationDetent` enum PresentationDetent: Hashable { ɾɾɾ } @available(iOS 16.0, *) extension PresentationDetent { var detent: SwiftUI.PresentationDetent { switch self { case .medium: return .medium ɾɾɾ } } }
  21. QSFTFOUBUJPO%FUFOUT .JOJNVN%FQMPZNFOU5BSHFUΛʹ͢ΔͱϏϧυΤϥʔ struct ContentView: View { @State private var isPresenting

    = false var body: some View { VStack { Button { isPresenting = true } label: { VStack { Image(systemName: "globe") .imageScale(.large) Text("Hello, world!") }.foregroundColor(.accentColor) .padding() } .sheet(isPresented: $isPresenting) { SheetView() .presentationDetents([.medium]) / / ← Ambiguous use of 'medium' } } } } @available(iOS, deprecated: 16, message: "Use `presentationDetents` in SwiftUI directly.") extension View { @ViewBuilder func presentationDetents(_ detents: Set<PresentationDetent>) -> some View { if #available(iOS 16.0, *) { presentationDetents(Set(detents.map(\.detent))) } else { self } } } /// Backporting for `SwiftUI.PresentationDetent` enum PresentationDetent: Hashable { ɾɾɾ } @available(iOS 16.0, *) extension PresentationDetent { var detent: SwiftUI.PresentationDetent { switch self { case .medium: return .medium ɾɾɾ } } }
  22. QSFTFOUBUJPO%FUFOUT CBDLQPSUGVODUJPOΛফͤ͹ܯࠂ΋ফ͑Δ struct ContentView: View { @State private var isPresenting

    = false var body: some View { VStack { Button { isPresenting = true } label: { VStack { Image(systemName: "globe") .imageScale(.large) Text("Hello, world!") }.foregroundColor(.accentColor) .padding() } .sheet(isPresented: $isPresenting) { SheetView() .presentationDetents([.medium]) } } } } //@available(iOS, obsoleted: 16, message: "Use `presentationDetents` in SwiftUI directly.") //extension View { // @ViewBuilder // func presentationDetents(_ detents: Set<PresentationDetent>) -> some View { // if #available(iOS 16.0, *) { // presentationDetents(Set(detents.map(\.detent))) // } else { // self // } // } //} // ///// Backporting for `SwiftUI.PresentationDetent` //enum PresentationDetent: Hashable { // ɾɾɾ //} // //@available(iOS 16.0, *) //extension PresentationDetent { // var detent: SwiftUI.PresentationDetent { // switch self { // case .medium: return .medium // ɾɾɾ // } // } //}