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

Como hacer coexistir CocoaPods y SPM

Como hacer coexistir CocoaPods y SPM

En esta presentación se explica cómo hacer convivir dependencias obtenidas a través de cocoapods en Swift Package Manager.

Presentado en el meetup iOS organizado por Accenture el 25 de agosto de 2022

Avatar for Bastián Véliz

Bastián Véliz

August 25, 2022

More Decks by Bastián Véliz

Other Decks in Technology

Transcript

  1. ¿Cómo hacer convivir Cocoapods y SPM en un mismo proyecto?

    Y no morir en el intento Bastián Véliz Vega
  2. ¿Qué veremos hoy? Agenda CocoaPods y SPM en contexto Proyecto

    de ejemplo y sus dependencias El problema La propuesta Manos a la obra Demo Conclusiones #1 #2 #3 #4 #5 #6 #7 2
  3. Ruby Inspirado en RubyGems y Bundler 11 Años Primer release:

    1 de Septiembre De 2011 Lenguajes • Objective-C • Swift Distribución • Código fuente • .framework • .a • .xcframework CocoaPods 4
  4. Swift • Server Side • iOS • macOS • tvOS

    • watchOS 7 Años Primer release: 3 de Diciembre De 2011 Lenguajes • Swift • Objective-C Distribución • Código fuente • .xcframework Swift Package Manager 5
  5. Swift Package Manager Swift 3.0 Swift 4.0 Swift 4.2 Swift

    5.0 Swift 5.0 Evolución 6 Solo compatible con Server Side Swift Soporte para ramas en dependencias (SE-0150) Soporte para C/C++ (SE-0181) Soporte para dependencias locales (SE-021) Soporte para plataformas Apple (SE-0236)
  6. Swift Package Manager Swift 5.3 Swift 5.3 Swift 5.3 Swift

    5.6 Swift 6.x Evolución 7 Soporte para recursos (SE-0271) Soporte para dependencias binarias (SE-0272) Soporte para recursos localizables (SE-0278) Soporte para plugins (SE-0303, SE-0305, SE-0325, SE-0332) ¿?
  7. Proyecto de ejemplo 18 AudioDetail Networking Search Pods ItunesExample 􀈖

    ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent
  8. Proyecto de ejemplo 19 AudioDetail Networking Search Pods ItunesExample 􀈖

    ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent ItunesExampleApp.swift import SwiftUI import Search @main struct ItunesExampleApp: App { var body: some Scene { WindowGroup { SearchView() } } }
  9. Proyecto de ejemplo 20 AudioDetail Networking Search Pods ItunesExample 􀈖

    ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent ItunesExampleApp.swift import SwiftUI import Search @main struct ItunesExampleApp: App { var body: some Scene { WindowGroup { SearchView() } } }
  10. Proyecto de ejemplo 21 AudioDetail Networking Search Pods ItunesExample 􀈖

    ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 Search 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 SearchBar 􀫊 SearchViewCell 􀫊 SearchView
  11. Proyecto de ejemplo 22 AudioDetail Networking Search Pods ItunesExample 􀈖

    ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 Search 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 SearchBar 􀫊 SearchViewCell 􀫊 SearchView SearchView.swift import AudioDetail import Foundation import SwiftUI public struct SearchView: View { @ObservedObject private var viewModel = SearchViewModel() init(viewModel: SearchViewModel) { self.viewModel = viewModel } public init() { self.init(viewModel: SearchViewModel()) } public var body: some View { NavigationView { VStack { SearchBar(text: self.$viewModel.text, placeholder: "search an artist") Picker("Search type", selection: self.$viewModel.searchType) { Text("Audio").tag(SearchType.music.rawValue) Text("Music Video").tag(SearchType.musicVideo.rawValue) Text("TV Show").tag(SearchType.tvShow.rawValue) } .pickerStyle(.segmented) .padding([.leading, .trailing]) self.viewForState } .navigationBarTitle("Itunes Search") } } @ViewBuilder var viewForState: some View { { ... } } }
  12. Proyecto de ejemplo 23 AudioDetail Networking Search Pods ItunesExample 􀈖

    ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 Search 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 SearchBar 􀫊 SearchViewCell 􀫊 SearchView SearchView.swift import AudioDetail import Foundation import SwiftUI public struct SearchView: View { @ObservedObject private var viewModel = SearchViewModel() init(viewModel: SearchViewModel) { self.viewModel = viewModel } public init() { self.init(viewModel: SearchViewModel()) } public var body: some View { NavigationView { VStack { SearchBar(text: self.$viewModel.text, placeholder: "search an artist") Picker("Search type", selection: self.$viewModel.searchType) { Text("Audio").tag(SearchType.music.rawValue) Text("Music Video").tag(SearchType.musicVideo.rawValue) Text("TV Show").tag(SearchType.tvShow.rawValue) } .pickerStyle(.segmented) .padding([.leading, .trailing]) self.viewForState } .navigationBarTitle("Itunes Search") } } @ViewBuilder var viewForState: some View { { ... } } }
  13. Proyecto de ejemplo 24 AudioDetail Networking Search Pods ItunesExample 􀈖

    ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 Search 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 SearchBar 􀫊 SearchViewCell 􀫊 SearchView SearchView.swift import AudioDetail import Foundation import SwiftUI public struct SearchView: View { @ObservedObject private var viewModel = SearchViewModel() init(viewModel: SearchViewModel) { self.viewModel = viewModel } public init() { self.init(viewModel: SearchViewModel()) } public var body: some View { NavigationView { VStack { SearchBar(text: self.$viewModel.text, placeholder: "search an artist") Picker("Search type", selection: self.$viewModel.searchType) { Text("Audio").tag(SearchType.music.rawValue) Text("Music Video").tag(SearchType.musicVideo.rawValue) Text("TV Show").tag(SearchType.tvShow.rawValue) } .pickerStyle(.segmented) .padding([.leading, .trailing]) self.viewForState } .navigationBarTitle("Itunes Search") } } @ViewBuilder var viewForState: some View { { ... } } }
  14. Proyecto de ejemplo 25 AudioDetail Networking Search Pods ItunesExample 􀈖

    ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 Search 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 SearchBar 􀫊 SearchViewCell 􀫊 SearchView SearchView.swift import AudioDetail import Foundation import SwiftUI public struct SearchView: View { @ObservedObject private var viewModel = SearchViewModel() init(viewModel: SearchViewModel) { self.viewModel = viewModel } public init() { self.init(viewModel: SearchViewModel()) } public var body: some View { NavigationView { VStack { SearchBar(text: self.$viewModel.text, placeholder: "search an artist") Picker("Search type", selection: self.$viewModel.searchType) { Text("Audio").tag(SearchType.music.rawValue) Text("Music Video").tag(SearchType.musicVideo.rawValue) Text("TV Show").tag(SearchType.tvShow.rawValue) } .pickerStyle(.segmented) .padding([.leading, .trailing]) self.viewForState } .navigationBarTitle("Itunes Search") } } @ViewBuilder var viewForState: some View { { ... } } }
  15. Proyecto de ejemplo 26 AudioDetail Networking Search Pods ItunesExample 􀈖

    ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 Search 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 SearchBar 􀫊 SearchViewCell 􀫊 SearchView SearchView.swift import AudioDetail import Foundation import SwiftUI public struct SearchView: View { @ObservedObject private var viewModel = SearchViewModel() init(viewModel: SearchViewModel) { self.viewModel = viewModel } public init() { self.init(viewModel: SearchViewModel()) } public var body: some View { NavigationView { VStack { SearchBar(text: self.$viewModel.text, placeholder: "search an artist") Picker("Search type", selection: self.$viewModel.searchType) { Text("Audio").tag(SearchType.music.rawValue) Text("Music Video").tag(SearchType.musicVideo.rawValue) Text("TV Show").tag(SearchType.tvShow.rawValue) } .pickerStyle(.segmented) .padding([.leading, .trailing]) self.viewForState } .navigationBarTitle("Itunes Search") } } @ViewBuilder var viewForState: some View { { ... } } }
  16. Proyecto de ejemplo 27 AudioDetail Networking Search Pods ItunesExample 􀈖

    ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 Search 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 SearchBar 􀫊 SearchViewCell 􀫊 SearchView SearchView.swift import AudioDetail import Foundation import SwiftUI public struct SearchView: View { { ... } @ViewBuilder var viewForState: some View { switch self.viewModel.state { case .loading: Text("Loading...") .frame(minHeight: 0, maxHeight: .infinity) case let .error(error): Text("Error: \(error.localizedDescription)") .frame(minHeight: 0, maxHeight: .infinity) case let .withData(elements): { ... } case .initial: Text("Type an artist or song in search bar") .frame(minHeight: 0, maxHeight: .infinity) } } }
  17. Proyecto de ejemplo 28 AudioDetail Networking Search Pods ItunesExample 􀈖

    ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 Search 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 SearchBar 􀫊 SearchViewCell 􀫊 SearchView SearchView.swift import AudioDetail import Foundation import SwiftUI public struct SearchView: View { { ... } @ViewBuilder var viewForState: some View { switch self.viewModel.state { case .loading: Text("Loading...") .frame(minHeight: 0, maxHeight: .infinity) case let .error(error): Text("Error: \(error.localizedDescription)") .frame(minHeight: 0, maxHeight: .infinity) case let .withData(elements): { ... } case .initial: Text("Type an artist or song in search bar") .frame(minHeight: 0, maxHeight: .infinity) } } }
  18. Proyecto de ejemplo 29 AudioDetail Networking Search Pods ItunesExample 􀈖

    ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 Search 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 SearchBar 􀫊 SearchViewCell 􀫊 SearchView SearchView.swift import AudioDetail import Foundation import SwiftUI public struct SearchView: View { { ... } @ViewBuilder var viewForState: some View { switch self.viewModel.state { case .loading: Text("Loading...") .frame(minHeight: 0, maxHeight: .infinity) case let .error(error): Text("Error: \(error.localizedDescription)") .frame(minHeight: 0, maxHeight: .infinity) case let .withData(elements): { ... } case .initial: Text("Type an artist or song in search bar") .frame(minHeight: 0, maxHeight: .infinity) } } }
  19. Proyecto de ejemplo 30 AudioDetail Networking Search Pods ItunesExample 􀈖

    ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 Search 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 SearchBar 􀫊 SearchViewCell 􀫊 SearchView SearchView.swift import AudioDetail import Foundation import SwiftUI public struct SearchView: View { { ... } @ViewBuilder var viewForState: some View { switch self.viewModel.state { case .loading: Text("Loading...") .frame(minHeight: 0, maxHeight: .infinity) case let .error(error): Text("Error: \(error.localizedDescription)") .frame(minHeight: 0, maxHeight: .infinity) case let .withData(elements): { ... } case .initial: Text("Type an artist or song in search bar") .frame(minHeight: 0, maxHeight: .infinity) } } }
  20. Proyecto de ejemplo 31 AudioDetail Networking Search Pods ItunesExample 􀈖

    ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 Search 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 SearchBar 􀫊 SearchViewCell 􀫊 SearchView SearchView.swift import AudioDetail import Foundation import SwiftUI public struct SearchView: View { { ... } @ViewBuilder var viewForState: some View { switch self.viewModel.state { case .loading: Text("Loading...") .frame(minHeight: 0, maxHeight: .infinity) case let .error(error): Text("Error: \(error.localizedDescription)") .frame(minHeight: 0, maxHeight: .infinity) case let .withData(elements): { ... } case .initial: Text("Type an artist or song in search bar") .frame(minHeight: 0, maxHeight: .infinity) } } }
  21. Proyecto de ejemplo 32 AudioDetail Networking Search Pods ItunesExample 􀈖

    ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 Search 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 SearchBar 􀫊 SearchViewCell 􀫊 SearchView SearchView.swift import AudioDetail import Foundation import SwiftUI public struct SearchView: View { { ... } @ViewBuilder var viewForState: some View { switch self.viewModel.state { case .loading: Text("Loading...") .frame(minHeight: 0, maxHeight: .infinity) case let .error(error): Text("Error: \(error.localizedDescription)") .frame(minHeight: 0, maxHeight: .infinity) case let .withData(elements): { ... } case .initial: Text("Type an artist or song in search bar") .frame(minHeight: 0, maxHeight: .infinity) } } }
  22. Proyecto de ejemplo 33 AudioDetail Networking Search Pods ItunesExample 􀈖

    ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 Search 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 SearchBar 􀫊 SearchViewCell 􀫊 SearchView SearchView.swift import AudioDetail import Foundation import SwiftUI public struct SearchView: View { { ... } @ViewBuilder var viewForState: some View { switch self.viewModel.state { { ... } case let .withData(elements): if elements.isEmpty { Text("No results") .frame(minHeight: 0, maxHeight: .infinity) } else { VStack { List { ForEach(elements, id: \.id) { item in switch item.type { case .music: NavigationLink(destination: AudioDetailView(trackId: item.trackId)) { SearchViewCell(model: item) } default: NavigationLink(destination: Text("Coming soon..")) { SearchViewCell(model: item) } } } } } } { ... } } } }
  23. Proyecto de ejemplo 34 AudioDetail Networking Search Pods ItunesExample 􀈖

    ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 Search 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 SearchBar 􀫊 SearchViewCell 􀫊 SearchView SearchView.swift import AudioDetail import Foundation import SwiftUI public struct SearchView: View { { ... } @ViewBuilder var viewForState: some View { switch self.viewModel.state { { ... } case let .withData(elements): if elements.isEmpty { Text("No results") .frame(minHeight: 0, maxHeight: .infinity) } else { VStack { List { ForEach(elements, id: \.id) { item in switch item.type { case .music: NavigationLink(destination: AudioDetailView(trackId: item.trackId)) { SearchViewCell(model: item) } default: NavigationLink(destination: Text("Coming soon..")) { SearchViewCell(model: item) } } } } } } { ... } } } }
  24. Proyecto de ejemplo 35 AudioDetail Networking Search Pods ItunesExample 􀈖

    ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 Search 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 SearchBar 􀫊 SearchViewCell 􀫊 SearchView SearchView.swift import AudioDetail import Foundation import SwiftUI public struct SearchView: View { { ... } @ViewBuilder var viewForState: some View { switch self.viewModel.state { { ... } case let .withData(elements): if elements.isEmpty { Text("No results") .frame(minHeight: 0, maxHeight: .infinity) } else { VStack { List { ForEach(elements, id: \.id) { item in switch item.type { case .music: NavigationLink(destination: AudioDetailView(trackId: item.trackId)) { SearchViewCell(model: item) } default: NavigationLink(destination: Text("Coming soon..")) { SearchViewCell(model: item) } } } } } } { ... } } } }
  25. Proyecto de ejemplo 36 AudioDetail Networking Search Pods ItunesExample 􀈖

    ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 Search 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 SearchBar 􀫊 SearchViewCell 􀫊 SearchView SearchView.swift import AudioDetail import Foundation import SwiftUI public struct SearchView: View { { ... } @ViewBuilder var viewForState: some View { switch self.viewModel.state { { ... } case let .withData(elements): if elements.isEmpty { Text("No results") .frame(minHeight: 0, maxHeight: .infinity) } else { VStack { List { ForEach(elements, id: \.id) { item in switch item.type { case .music: NavigationLink(destination: AudioDetailView(trackId: item.trackId)) { SearchViewCell(model: item) } default: NavigationLink(destination: Text("Coming soon..")) { SearchViewCell(model: item) } } } } } } { ... } } } }
  26. Proyecto de ejemplo 37 AudioDetail Networking Search Pods ItunesExample 􀈖

    ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 Search 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 SearchBar 􀫊 SearchViewCell 􀫊 SearchView SearchView.swift import AudioDetail import Foundation import SwiftUI public struct SearchView: View { { ... } @ViewBuilder var viewForState: some View { switch self.viewModel.state { { ... } case let .withData(elements): if elements.isEmpty { Text("No results") .frame(minHeight: 0, maxHeight: .infinity) } else { VStack { List { ForEach(elements, id: \.id) { item in switch item.type { case .music: NavigationLink(destination: AudioDetailView(trackId: item.trackId)) { SearchViewCell(model: item) } default: NavigationLink(destination: Text("Coming soon..")) { SearchViewCell(model: item) } } } } } } { ... } } } }
  27. Proyecto de ejemplo 38 AudioDetail Networking Search Pods ItunesExample 􀈖

    ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 Search 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 SearchBar 􀫊 SearchViewCell 􀫊 SearchView SearchView.swift import AudioDetail import Foundation import SwiftUI public struct SearchView: View { { ... } @ViewBuilder var viewForState: some View { switch self.viewModel.state { { ... } case let .withData(elements): if elements.isEmpty { Text("No results") .frame(minHeight: 0, maxHeight: .infinity) } else { VStack { List { ForEach(elements, id: \.id) { item in switch item.type { case .music: NavigationLink(destination: AudioDetailView(trackId: item.trackId)) { SearchViewCell(model: item) } default: NavigationLink(destination: Text("Coming soon..")) { SearchViewCell(model: item) } } } } } } { ... } } } }
  28. Proyecto de ejemplo 39 AudioDetail Networking Search Pods ItunesExample 􀈖

    ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 Search 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 SearchBar 􀫊 SearchViewCell 􀫊 SearchView SearchView.swift import AudioDetail import Foundation import SwiftUI public struct SearchView: View { { ... } @ViewBuilder var viewForState: some View { switch self.viewModel.state { { ... } case let .withData(elements): if elements.isEmpty { Text("No results") .frame(minHeight: 0, maxHeight: .infinity) } else { VStack { List { ForEach(elements, id: \.id) { item in switch item.type { case .music: NavigationLink(destination: AudioDetailView(trackId: item.trackId)) { SearchViewCell(model: item) } default: NavigationLink(destination: Text("Coming soon..")) { SearchViewCell(model: item) } } } } } } { ... } } } }
  29. Proyecto de ejemplo 40 SearchView.swift import AudioDetail import Foundation import

    SwiftUI public struct SearchView: View { { ... } @ViewBuilder var viewForState: some View { switch self.viewModel.state { { ... } case let .withData(elements): if elements.isEmpty { Text("No results") .frame(minHeight: 0, maxHeight: .infinity) } else { VStack { List { ForEach(elements, id: \.id) { item in switch item.type { case .music: NavigationLink(destination: AudioDetailView(trackId: item.trackId)) { SearchViewCell(model: item) } default: NavigationLink(destination: Text("Coming soon..")) { SearchViewCell(model: item) } } } } } } { ... } } } } AudioDetail Networking Search Pods ItunesExample 􀈖 ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 AudioDetail 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 AudioDetailView
  30. Proyecto de ejemplo 41 AudioDetailView.swift import SDWebImageSwiftUI import SwiftUI public

    struct AudioDetailView: View { @ObservedObject private var viewModel: AudioDetailViewModel private let trackId: Int64 init(trackId: Int64, viewModel: AudioDetailViewModel) { self.trackId = trackId self.viewModel = viewModel } public init(trackId: Int64) { self.init(trackId: trackId, viewModel: AudioDetailViewModel()) } public var body: some View { self.viewForState .onAppear { self.viewModel.loadDetail(trackId: self.trackId) } } @ViewBuilder var viewForState: some View { switch self.viewModel.state { case .loading: Text("Loading...") .frame(minHeight: 0, maxHeight: .infinity) case let .error(error): Text("Error: \(error.localizedDescription)") .frame(minHeight: 0, maxHeight: .infinity) case let .withData(model): self.getDetailView(model: model) } } func getDetailView(model: AudioDetailModel) -> some View { { ... } } } AudioDetail Networking Search Pods ItunesExample 􀈖 ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 AudioDetail 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 AudioDetailView
  31. Proyecto de ejemplo 42 AudioDetailView.swift import SDWebImageSwiftUI import SwiftUI public

    struct AudioDetailView: View { @ObservedObject private var viewModel: AudioDetailViewModel private let trackId: Int64 init(trackId: Int64, viewModel: AudioDetailViewModel) { self.trackId = trackId self.viewModel = viewModel } public init(trackId: Int64) { self.init(trackId: trackId, viewModel: AudioDetailViewModel()) } public var body: some View { self.viewForState .onAppear { self.viewModel.loadDetail(trackId: self.trackId) } } @ViewBuilder var viewForState: some View { switch self.viewModel.state { case .loading: Text("Loading...") .frame(minHeight: 0, maxHeight: .infinity) case let .error(error): Text("Error: \(error.localizedDescription)") .frame(minHeight: 0, maxHeight: .infinity) case let .withData(model): self.getDetailView(model: model) } } func getDetailView(model: AudioDetailModel) -> some View { { ... } } } AudioDetail Networking Search Pods ItunesExample 􀈖 ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 AudioDetail 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 AudioDetailView
  32. Proyecto de ejemplo 43 AudioDetailView.swift import SDWebImageSwiftUI import SwiftUI public

    struct AudioDetailView: View { @ObservedObject private var viewModel: AudioDetailViewModel private let trackId: Int64 init(trackId: Int64, viewModel: AudioDetailViewModel) { self.trackId = trackId self.viewModel = viewModel } public init(trackId: Int64) { self.init(trackId: trackId, viewModel: AudioDetailViewModel()) } public var body: some View { self.viewForState .onAppear { self.viewModel.loadDetail(trackId: self.trackId) } } @ViewBuilder var viewForState: some View { switch self.viewModel.state { case .loading: Text("Loading...") .frame(minHeight: 0, maxHeight: .infinity) case let .error(error): Text("Error: \(error.localizedDescription)") .frame(minHeight: 0, maxHeight: .infinity) case let .withData(model): self.getDetailView(model: model) } } func getDetailView(model: AudioDetailModel) -> some View { { ... } } } AudioDetail Networking Search Pods ItunesExample 􀈖 ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 AudioDetail 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 AudioDetailView
  33. Proyecto de ejemplo 44 AudioDetailView.swift import SDWebImageSwiftUI import SwiftUI public

    struct AudioDetailView: View { @ObservedObject private var viewModel: AudioDetailViewModel private let trackId: Int64 init(trackId: Int64, viewModel: AudioDetailViewModel) { self.trackId = trackId self.viewModel = viewModel } public init(trackId: Int64) { self.init(trackId: trackId, viewModel: AudioDetailViewModel()) } public var body: some View { self.viewForState .onAppear { self.viewModel.loadDetail(trackId: self.trackId) } } @ViewBuilder var viewForState: some View { switch self.viewModel.state { case .loading: Text("Loading...") .frame(minHeight: 0, maxHeight: .infinity) case let .error(error): Text("Error: \(error.localizedDescription)") .frame(minHeight: 0, maxHeight: .infinity) case let .withData(model): self.getDetailView(model: model) } } func getDetailView(model: AudioDetailModel) -> some View { { ... } } } AudioDetail Networking Search Pods ItunesExample 􀈖 ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 AudioDetail 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 AudioDetailView
  34. Proyecto de ejemplo 45 AudioDetailView.swift import SDWebImageSwiftUI import SwiftUI public

    struct AudioDetailView: View { @ObservedObject private var viewModel: AudioDetailViewModel private let trackId: Int64 init(trackId: Int64, viewModel: AudioDetailViewModel) { self.trackId = trackId self.viewModel = viewModel } public init(trackId: Int64) { self.init(trackId: trackId, viewModel: AudioDetailViewModel()) } public var body: some View { self.viewForState .onAppear { self.viewModel.loadDetail(trackId: self.trackId) } } @ViewBuilder var viewForState: some View { switch self.viewModel.state { case .loading: Text("Loading...") .frame(minHeight: 0, maxHeight: .infinity) case let .error(error): Text("Error: \(error.localizedDescription)") .frame(minHeight: 0, maxHeight: .infinity) case let .withData(model): self.getDetailView(model: model) } } func getDetailView(model: AudioDetailModel) -> some View { { ... } } } AudioDetail Networking Search Pods ItunesExample 􀈖 ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 AudioDetail 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 AudioDetailView
  35. Proyecto de ejemplo 46 AudioDetailView.swift import SDWebImageSwiftUI import SwiftUI public

    struct AudioDetailView: View { @ObservedObject private var viewModel: AudioDetailViewModel private let trackId: Int64 init(trackId: Int64, viewModel: AudioDetailViewModel) { self.trackId = trackId self.viewModel = viewModel } public init(trackId: Int64) { self.init(trackId: trackId, viewModel: AudioDetailViewModel()) } public var body: some View { self.viewForState .onAppear { self.viewModel.loadDetail(trackId: self.trackId) } } @ViewBuilder var viewForState: some View { switch self.viewModel.state { case .loading: Text("Loading...") .frame(minHeight: 0, maxHeight: .infinity) case let .error(error): Text("Error: \(error.localizedDescription)") .frame(minHeight: 0, maxHeight: .infinity) case let .withData(model): self.getDetailView(model: model) } } func getDetailView(model: AudioDetailModel) -> some View { { ... } } } AudioDetail Networking Search Pods ItunesExample 􀈖 ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 AudioDetail 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 AudioDetailView
  36. Proyecto de ejemplo 47 AudioDetailView.swift import SDWebImageSwiftUI import SwiftUI public

    struct AudioDetailView: View { @ObservedObject private var viewModel: AudioDetailViewModel private let trackId: Int64 init(trackId: Int64, viewModel: AudioDetailViewModel) { self.trackId = trackId self.viewModel = viewModel } public init(trackId: Int64) { self.init(trackId: trackId, viewModel: AudioDetailViewModel()) } public var body: some View { self.viewForState .onAppear { self.viewModel.loadDetail(trackId: self.trackId) } } @ViewBuilder var viewForState: some View { switch self.viewModel.state { case .loading: Text("Loading...") .frame(minHeight: 0, maxHeight: .infinity) case let .error(error): Text("Error: \(error.localizedDescription)") .frame(minHeight: 0, maxHeight: .infinity) case let .withData(model): self.getDetailView(model: model) } } func getDetailView(model: AudioDetailModel) -> some View { { ... } } } AudioDetail Networking Search Pods ItunesExample 􀈖 ItunesExample 􀫊 ItunesExampleApp 􀣵 Assets 􀈖 PreviewContent 􀈖 AudioDetail 􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 AudioDetailView
  37. Dependencias 51 ItunesExample AudioDetail Networking Search Pods 􀈖 Frameworks 􀈖

    Pods 􀈖 Products 􀈖 Targets Support Files Podfile Podfile platform :ios, '15.0' use_frameworks! workspace 'ItunesExample.xcworkspace' def test_pods pod "Quick" pod "Nimble" end def snapshot_test_pods test_pods pod "Nimble-Snapshots" end target 'ItunesExample' do project 'ItunesExample.xcodeproj' pod 'SDWebImageSwiftUI' target 'ItunesExampleTests' do inherit! :search_paths snapshot_test_pods end target 'ItunesExampleUITests' do # Pods for testing end end
  38. Dependencias 52 ItunesExample AudioDetail Networking Search Pods 􀈖 Frameworks 􀈖

    Pods 􀈖 Products 􀈖 Targets Support Files Podfile Podfile platform :ios, '15.0' use_frameworks! workspace 'ItunesExample.xcworkspace' def test_pods pod "Quick" pod "Nimble" end def snapshot_test_pods test_pods pod "Nimble-Snapshots" end target 'ItunesExample' do project 'ItunesExample.xcodeproj' pod 'SDWebImageSwiftUI' target 'ItunesExampleTests' do inherit! :search_paths snapshot_test_pods end target 'ItunesExampleUITests' do # Pods for testing end end
  39. Dependencias 53 ItunesExample AudioDetail Networking Search Pods 􀈖 Frameworks 􀈖

    Pods 􀈖 Products 􀈖 Targets Support Files Podfile Podfile platform :ios, '15.0' use_frameworks! workspace 'ItunesExample.xcworkspace' def test_pods pod "Quick" pod "Nimble" end def snapshot_test_pods test_pods pod "Nimble-Snapshots" end target 'ItunesExample' do project 'ItunesExample.xcodeproj' pod 'SDWebImageSwiftUI' target 'ItunesExampleTests' do inherit! :search_paths snapshot_test_pods end target 'ItunesExampleUITests' do # Pods for testing end end
  40. Dependencias 54 ItunesExample AudioDetail Networking Search Pods 􀈖 Frameworks 􀈖

    Pods 􀈖 Products 􀈖 Targets Support Files Podfile Podfile platform :ios, '15.0' use_frameworks! workspace 'ItunesExample.xcworkspace' def test_pods pod "Quick" pod "Nimble" end def snapshot_test_pods test_pods pod "Nimble-Snapshots" end target 'ItunesExample' do project 'ItunesExample.xcodeproj' pod 'SDWebImageSwiftUI' target 'ItunesExampleTests' do inherit! :search_paths snapshot_test_pods end target 'ItunesExampleUITests' do # Pods for testing end end
  41. Dependencias 55 ItunesExample AudioDetail Networking Search Pods 􀈖 Frameworks 􀈖

    Pods 􀈖 Products 􀈖 Targets Support Files Podfile Podfile platform :ios, '15.0' use_frameworks! workspace 'ItunesExample.xcworkspace' def test_pods pod "Quick" pod "Nimble" end def snapshot_test_pods test_pods pod "Nimble-Snapshots" end target 'ItunesExample' do project 'ItunesExample.xcodeproj' pod 'SDWebImageSwiftUI' target 'ItunesExampleTests' do inherit! :search_paths snapshot_test_pods end target 'ItunesExampleUITests' do # Pods for testing end end
  42. Dependencias 56 ItunesExample AudioDetail Networking Search Pods 􀈖 Frameworks 􀈖

    Pods 􀈖 Products 􀈖 Targets Support Files Podfile Podfile platform :ios, '15.0' use_frameworks! workspace 'ItunesExample.xcworkspace' def test_pods pod "Quick" pod "Nimble" end def snapshot_test_pods test_pods pod "Nimble-Snapshots" end target 'ItunesExample' do project 'ItunesExample.xcodeproj' pod 'SDWebImageSwiftUI' target 'ItunesExampleTests' do inherit! :search_paths snapshot_test_pods end target 'ItunesExampleUITests' do # Pods for testing end end
  43. Dependencias 57 ItunesExample AudioDetail Networking Search Pods 􀈖 Frameworks 􀈖

    Pods 􀈖 Products 􀈖 Targets Support Files Podfile Podfile target 'Networking' do project 'Networking/Networking.xcodeproj' target 'NetworkingTests' do inherit! :search_paths test_pods end end target 'Search' do project 'Search/Search.xcodeproj' pod 'SDWebImageSwiftUI' target 'SearchTests' do inherit! :search_paths snapshot_test_pods end end target 'AudioDetail' do project 'AudioDetail/AudioDetail.xcodeproj' pod 'SDWebImageSwiftUI' target 'AudioDetailTests' do inherit! :search_paths snapshot_test_pods end end
  44. Dependencias 58 ItunesExample AudioDetail Networking Search Pods 􀈖 Frameworks 􀈖

    Pods 􀈖 Products 􀈖 Targets Support Files Podfile Podfile target 'Networking' do project 'Networking/Networking.xcodeproj' target 'NetworkingTests' do inherit! :search_paths test_pods end end target 'Search' do project 'Search/Search.xcodeproj' pod 'SDWebImageSwiftUI' target 'SearchTests' do inherit! :search_paths snapshot_test_pods end end target 'AudioDetail' do project 'AudioDetail/AudioDetail.xcodeproj' pod 'SDWebImageSwiftUI' target 'AudioDetailTests' do inherit! :search_paths snapshot_test_pods end end
  45. Dependencias 59 ItunesExample AudioDetail Networking Search Pods 􀈖 Frameworks 􀈖

    Pods 􀈖 Products 􀈖 Targets Support Files Podfile Podfile target 'Networking' do project 'Networking/Networking.xcodeproj' target 'NetworkingTests' do inherit! :search_paths test_pods end end target 'Search' do project 'Search/Search.xcodeproj' pod 'SDWebImageSwiftUI' target 'SearchTests' do inherit! :search_paths snapshot_test_pods end end target 'AudioDetail' do project 'AudioDetail/AudioDetail.xcodeproj' pod 'SDWebImageSwiftUI' target 'AudioDetailTests' do inherit! :search_paths snapshot_test_pods end end
  46. Dependencias 60 ItunesExample AudioDetail Networking Search Pods 􀈖 Frameworks 􀈖

    Pods 􀈖 Products 􀈖 Targets Support Files Podfile Podfile target 'Networking' do project 'Networking/Networking.xcodeproj' target 'NetworkingTests' do inherit! :search_paths test_pods end end target 'Search' do project 'Search/Search.xcodeproj' pod 'SDWebImageSwiftUI' target 'SearchTests' do inherit! :search_paths snapshot_test_pods end end target 'AudioDetail' do project 'AudioDetail/AudioDetail.xcodeproj' pod 'SDWebImageSwiftUI' target 'AudioDetailTests' do inherit! :search_paths snapshot_test_pods end end
  47. El problema 62 AudioDetail Networking Search Pods ItunesExample 􀈖 Search

    􀈖 Provider 􀈖 Service 􀈖 ViewModel 􀈖 Views 􀫊 SearchBar 􀫊 SearchViewCell 􀫊 SearchView SearchView.swift import AudioDetail import Foundation import SwiftUI public struct SearchView: View { { ... } @ViewBuilder var viewForState: some View { switch self.viewModel.state { { ... } case let .withData(elements): if elements.isEmpty { Text("No results") .frame(minHeight: 0, maxHeight: .infinity) } else { VStack { List { ForEach(elements, id: \.id) { item in switch item.type { case .music: NavigationLink(destination: AudioDetailView(trackId: item.trackId)) { SearchViewCell(model: item) } default: NavigationLink(destination: Text("Coming soon..")) { SearchViewCell(model: item) } } } } } } { ... } } } }
  48. El problema 65 AudioDetail Networking Search Pods ItunesExample 􀐛 VideoDetail

    􀉚 README 􀫊 Package 􀣎 Sources 􀣎 Tests Package.swift // swift-tools-version: 5.6 import PackageDescription let package = Package( name: "VideoDetail", platforms: [ .iOS(.v15), ], products: [ .library( name: "VideoDetail", type: .dynamic, targets: ["VideoDetail"] ), ], dependencies: [ .package(url: "https://github.com/SDWebImage/SDWebImageSwiftUI.git", from: "2.0.0"), .package(url: "https://github.com/Quick/Quick.git", from: "5.0.0"), .package(url: "https://github.com/Quick/Nimble.git", from: "10.0.0"), .package(url: "https://github.com/ashfurrow/Nimble-Snapshots.git", from: "9.0.0"), ], targets: [ .target( name: "VideoDetail", dependencies: [ "SDWebImageSwiftUI", ] ), .testTarget( name: "VideoDetailTests", dependencies: [ "VideoDetail", "Quick", "Nimble", "Nimble-Snapshots", ] ), ] )
  49. Package.swift // swift-tools-version: 5.6 import PackageDescription let package = Package(

    name: "VideoDetail", platforms: [ .iOS(.v15), ], products: [ .library( name: "VideoDetail", type: .dynamic, targets: ["VideoDetail"] ), ], dependencies: [ .package(url: "https://github.com/SDWebImage/SDWebImageSwiftUI.git", from: "2.0.0"), .package(url: "https://github.com/Quick/Quick.git", from: "5.0.0"), .package(url: "https://github.com/Quick/Nimble.git", from: "10.0.0"), .package(url: "https://github.com/ashfurrow/Nimble-Snapshots.git", from: "9.0.0"), ], targets: [ .target( name: "VideoDetail", dependencies: [ "SDWebImageSwiftUI", ] ), .testTarget( name: "VideoDetailTests", dependencies: [ "VideoDetail", "Quick", "Nimble", "Nimble-Snapshots", ] ), ] ) El problema 66 AudioDetail Networking Search Pods ItunesExample 􀐛 VideoDetail 􀉚 README 􀫊 Package 􀣎 Sources 􀣎 Tests
  50. Package.swift // swift-tools-version: 5.6 import PackageDescription let package = Package(

    name: "VideoDetail", platforms: [ .iOS(.v15), ], products: [ .library( name: "VideoDetail", type: .dynamic, targets: ["VideoDetail"] ), ], dependencies: [ .package(url: "https://github.com/SDWebImage/SDWebImageSwiftUI.git", from: "2.0.0"), .package(url: "https://github.com/Quick/Quick.git", from: "5.0.0"), .package(url: "https://github.com/Quick/Nimble.git", from: "10.0.0"), .package(url: "https://github.com/ashfurrow/Nimble-Snapshots.git", from: "9.0.0"), ], targets: [ .target( name: "VideoDetail", dependencies: [ "SDWebImageSwiftUI", ] ), .testTarget( name: "VideoDetailTests", dependencies: [ "VideoDetail", "Quick", "Nimble", "Nimble-Snapshots", ] ), ] ) El problema 67 AudioDetail Networking Search Pods ItunesExample 􀐛 VideoDetail 􀉚 README 􀫊 Package 􀣎 Sources 􀣎 Tests
  51. Package.swift // swift-tools-version: 5.6 import PackageDescription let package = Package(

    name: "VideoDetail", platforms: [ .iOS(.v15), ], products: [ .library( name: "VideoDetail", type: .dynamic, targets: ["VideoDetail"] ), ], dependencies: [ .package(url: "https://github.com/SDWebImage/SDWebImageSwiftUI.git", from: "2.0.0"), .package(url: "https://github.com/Quick/Quick.git", from: "5.0.0"), .package(url: "https://github.com/Quick/Nimble.git", from: "10.0.0"), .package(url: "https://github.com/ashfurrow/Nimble-Snapshots.git", from: "9.0.0"), ], targets: [ .target( name: "VideoDetail", dependencies: [ "SDWebImageSwiftUI", ] ), .testTarget( name: "VideoDetailTests", dependencies: [ "VideoDetail", "Quick", "Nimble", "Nimble-Snapshots", ] ), ] ) El problema 68 AudioDetail Networking Search Pods ItunesExample 􀐛 VideoDetail 􀉚 README 􀫊 Package 􀣎 Sources 􀣎 Tests
  52. Package.swift // swift-tools-version: 5.6 import PackageDescription let package = Package(

    name: "VideoDetail", platforms: [ .iOS(.v15), ], products: [ .library( name: "VideoDetail", type: .dynamic, targets: ["VideoDetail"] ), ], dependencies: [ .package(url: "https://github.com/SDWebImage/SDWebImageSwiftUI.git", from: "2.0.0"), .package(url: "https://github.com/Quick/Quick.git", from: "5.0.0"), .package(url: "https://github.com/Quick/Nimble.git", from: "10.0.0"), .package(url: "https://github.com/ashfurrow/Nimble-Snapshots.git", from: "9.0.0"), ], targets: [ .target( name: "VideoDetail", dependencies: [ "SDWebImageSwiftUI", ] ), .testTarget( name: "VideoDetailTests", dependencies: [ "VideoDetail", "Quick", "Nimble", "Nimble-Snapshots", ] ), ] ) El problema 69 AudioDetail Networking Search Pods ItunesExample 􀐛 VideoDetail 􀉚 README 􀣎 Sources 􀣎 Tests 􀫊 Package
  53. Package.swift // swift-tools-version: 5.6 import PackageDescription let package = Package(

    name: "VideoDetail", platforms: [ .iOS(.v15), ], products: [ .library( name: "VideoDetail", type: .dynamic, targets: ["VideoDetail"] ), ], dependencies: [ .package(url: "https://github.com/SDWebImage/SDWebImageSwiftUI.git", from: "2.0.0"), .package(url: "https://github.com/Quick/Quick.git", from: "5.0.0"), .package(url: "https://github.com/Quick/Nimble.git", from: "10.0.0"), .package(url: "https://github.com/ashfurrow/Nimble-Snapshots.git", from: "9.0.0"), ], targets: [ .target( name: "VideoDetail", dependencies: [ "SDWebImageSwiftUI", ] ), .testTarget( name: "VideoDetailTests", dependencies: [ "VideoDetail", "Quick", "Nimble", "Nimble-Snapshots", ] ), ] ) El problema 70 AudioDetail Networking Search Pods ItunesExample 􀐛 VideoDetail 􀉚 README 􀫊 Package 􀣎 Sources 􀣎 Tests
  54. El problema 75 AudioDetail Networking Search Pods ItunesExample 􀐛 VideoDetail

    􀉚 README 􀫊 Package 􀣎 Sources 􀣎 Tests objc[92153]: Class _TtC17SDWebImageSwiftUI24AnimatedImageCoordinator is implemented in both /Users/ bastian.veliz.vega/DEV/personal/multidependency-example/DerivedData/ItunesExample/Build/Products/Debug- iphonesimulator/PackageFrameworks/VideoDetail.framework/VideoDetail (0x10b009818) and /Users/bastian.veliz.vega/ Library/Developer/CoreSimulator/Devices/C38246D5-1046-4E43-B0AC-CE7A9E765D47/data/Containers/Bundle/Application/ 845A79BA-B817-4B40-A1E5-7FEDF19103A0/ItunesExample.app/Frameworks/SDWebImageSwiftUI.framework/SDWebImageSwiftUI (0x10aca8d20). One of the two will be used. Which one is undefined.
  55. El problema 76 AudioDetail Networking Search Pods ItunesExample 􀐛 VideoDetail

    􀉚 README 􀫊 Package 􀣎 Sources 􀣎 Tests objc[92153]: Class _TtC17SDWebImageSwiftUI24AnimatedImageCoordinator is implemented in both /Users/ bastian.veliz.vega/DEV/personal/multidependency-example/DerivedData/ItunesExample/Build/Products/Debug- iphonesimulator/PackageFrameworks/VideoDetail.framework/VideoDetail (0x10b009818) and /Users/bastian.veliz.vega/ Library/Developer/CoreSimulator/Devices/C38246D5-1046-4E43-B0AC-CE7A9E765D47/data/Containers/Bundle/Application/ 845A79BA-B817-4B40-A1E5-7FEDF19103A0/ItunesExample.app/Frameworks/SDWebImageSwiftUI.framework/SDWebImageSwiftUI (0x10aca8d20). One of the two will be used. Which one is undefined. objc[92153]: Class _TtC17SDWebImageSwiftUI18AnimatedImageModel is implemented in both /Users/bastian.veliz.vega/DEV/ personal/multidependency-example/DerivedData/ItunesExample/Build/Products/Debug-iphonesimulator/PackageFrameworks/ VideoDetail.framework/VideoDetail (0x10b00b6a8) and /Users/bastian.veliz.vega/Library/Developer/CoreSimulator/ Devices/C38246D5-1046-4E43-B0AC-CE7A9E765D47/data/Containers/Bundle/Application/845A79BA-B817-4B40- A1E5-7FEDF19103A0/ItunesExample.app/Frameworks/SDWebImageSwiftUI.framework/SDWebImageSwiftUI (0x10aca9bc0). One of the two will be used. Which one is undefined. objc[92153]: Class _TtC17SDWebImageSwiftUI20AnimatedLoadingModel is implemented in both /Users/bastian.veliz.vega/ DEV/personal/multidependency-example/DerivedData/ItunesExample/Build/Products/Debug-iphonesimulator/ PackageFrameworks/VideoDetail.framework/VideoDetail (0x10b00b798) and /Users/bastian.veliz.vega/Library/Developer/ CoreSimulator/Devices/C38246D5-1046-4E43-B0AC-CE7A9E765D47/data/Containers/Bundle/Application/845A79BA-B817-4B40- A1E5-7FEDF19103A0/ItunesExample.app/Frameworks/SDWebImageSwiftUI.framework/SDWebImageSwiftUI (0x10aca9cb0). One of the two will be used. Which one is undefined. objc[92153]: Class _TtC17SDWebImageSwiftUI20AnimatedImageHandler is implemented in both /Users/bastian.veliz.vega/ DEV/personal/multidependency-example/DerivedData/ItunesExample/Build/Products/Debug-iphonesimulator/ PackageFrameworks/VideoDetail.framework/VideoDetail (0x10b00b8d8) and /Users/bastian.veliz.vega/Library/Developer/ CoreSimulator/Devices/C38246D5-1046-4E43-B0AC-CE7A9E765D47/data/Containers/Bundle/Application/845A79BA-B817-4B40- A1E5-7FEDF19103A0/ItunesExample.app/Frameworks/SDWebImageSwiftUI.framework/SDWebImageSwiftUI (0x10aca9df0). One of the two will be used. Which one is undefined. objc[92153]: Class _TtC17SDWebImageSwiftUI19AnimatedImageLayout is implemented in both /Users/bastian.veliz.vega/ DEV/personal/multidependency-example/DerivedData/ItunesExample/Build/Products/Debug-iphonesimulator/ PackageFrameworks/VideoDetail.framework/VideoDetail (0x10b00b9a8) and /Users/bastian.veliz.vega/Library/Developer/ CoreSimulator/Devices/C38246D5-1046-4E43-B0AC-CE7A9E765D47/data/Containers/Bundle/Application/845A79BA-B817-4B40- A1E5-7FEDF19103A0/ItunesExample.app/Frameworks/SDWebImageSwiftUI.framework/SDWebImageSwiftUI (0x10aca9ec0). One of the two will be used. Which one is undefined. objc[92153]: Class _TtC17SDWebImageSwiftUI26AnimatedImageConfiguration is implemented in both /Users/ bastian.veliz.vega/DEV/personal/multidependency-example/DerivedData/ItunesExample/Build/Products/Debug- iphonesimulator/PackageFrameworks/VideoDetail.framework/VideoDetail (0x10b00ba70) and /Users/bastian.veliz.vega/ Library/Developer/CoreSimulator/Devices/C38246D5-1046-4E43-B0AC-CE7A9E765D47/data/Containers/Bundle/Application/ 845A79BA-B817-4B40-A1E5-7FEDF19103A0/ItunesExample.app/Frameworks/SDWebImageSwiftUI.framework/SDWebImageSwiftUI (0x10aca9f88). One of the two will be used. Which one is undefined. objc[92153]: Class _TtC17SDWebImageSwiftUI12ImageManager is implemented in both /Users/bastian.veliz.vega/DEV/ personal/multidependency-example/DerivedData/ItunesExample/Build/Products/Debug-iphonesimulator/PackageFrameworks/ VideoDetail.framework/VideoDetail (0x10b00bc88) and /Users/bastian.veliz.vega/Library/Developer/CoreSimulator/
  56. El problema 83 Networking Search Pods AudioDetail ItunesExample 􀐛 VideoDetail

    􀈖 NetworkingTests 􀈖 Utils 􀈖 Fake 􀈖 Tests 􀈖 Networking NetworkClientTests.swift import Foundation import Nimble import Quick @testable import Networking class NetworkClientTests: QuickSpec { var sut: NetworkClient! var fakeURLSession: FakeURLSession! var fakeUrl = URL(string: "https://bing.com")! var fakeData = "hello".data(using: .utf8)! override func spec() { { ... } } } 􀫊 NetworkClientTests
  57. El problema 84 Networking Search Pods AudioDetail ItunesExample 􀐛 VideoDetail

    􀈖 NetworkingTests 􀈖 Utils 􀈖 Fake 􀈖 Tests 􀈖 Networking 􀫊 NetworkClientTests missing required module 'QuickObjCRuntime' 􀀳 NetworkClientTests.swift import Foundation import Nimble import Quick @testable import Networking class NetworkClientTests: QuickSpec { var sut: NetworkClient! var fakeURLSession: FakeURLSession! var fakeUrl = URL(string: "https://bing.com")! var fakeData = "hello".data(using: .utf8)! override func spec() { { ... } } }
  58. El problema • Gran cantidad de warnings al ejecutar la

    aplicación. • Proyecto no compila al querer correr las pruebas. • Dependencias de CocoaPods no “conversan” necesariamente con dependencias de SPM. • La estructura del proyecto debe ser capaz de que ambas herramientas (CocoaPods y SPM) puedan coexistir. ¿O los problemas? 85
  59. La propuesta 88 Swift 5.3 Soporte para dependencias binarias (SE-0272)

    Package.swift // swift-tools-version:5.6 import PackageDescription let package = Package( name: "MyLibrary", platforms: [ .macOS(.v10_14), .iOS(.v13), .tvOS(.v13) ], products: [ .library( name: "MyLibrary", targets: ["MyLibrary", "SomeRemoteBinaryPackage", "SomeLocalBinaryPackage"]) ], dependencies: [], targets: [ .target( name: "MyLibrary" ), .binaryTarget( name: "SomeRemoteBinaryPackage", url: "https://url/to/some/remote/xcframework.zip", checksum: "The checksum of the ZIP archive that contains the XCFramework." ), .binaryTarget( name: "SomeLocalBinaryPackage", path: "path/to/some.xcframework" ) .testTarget( name: "MyLibraryTests", dependencies: ["MyLibrary"]), ] )
  60. La propuesta 89 Swift 5.3 Soporte para dependencias binarias (SE-0272)

    Package.swift // swift-tools-version:5.6 import PackageDescription let package = Package( name: "MyLibrary", platforms: [ .macOS(.v10_14), .iOS(.v13), .tvOS(.v13) ], products: [ .library( name: "MyLibrary", targets: ["MyLibrary", "SomeRemoteBinaryPackage", "SomeLocalBinaryPackage"]) ], dependencies: [], targets: [ .target( name: "MyLibrary" ), .binaryTarget( name: "SomeRemoteBinaryPackage", url: "https://url/to/some/remote/xcframework.zip", checksum: "The checksum of the ZIP archive that contains the XCFramework." ), .binaryTarget( name: "SomeLocalBinaryPackage", path: "path/to/some.xcframework" ) .testTarget( name: "MyLibraryTests", dependencies: ["MyLibrary"]), ] )
  61. La propuesta 90 Swift 5.3 Soporte para dependencias binarias (SE-0272)

    Package.swift // swift-tools-version:5.6 import PackageDescription let package = Package( name: "MyLibrary", platforms: [ .macOS(.v10_14), .iOS(.v13), .tvOS(.v13) ], products: [ .library( name: "MyLibrary", targets: ["MyLibrary", "SomeRemoteBinaryPackage", "SomeLocalBinaryPackage"]) ], dependencies: [], targets: [ .target( name: "MyLibrary" ), .binaryTarget( name: "SomeRemoteBinaryPackage", url: "https://url/to/some/remote/xcframework.zip", checksum: "The checksum of the ZIP archive that contains the XCFramework." ), .binaryTarget( name: "SomeLocalBinaryPackage", path: "path/to/some.xcframework" ) .testTarget( name: "MyLibraryTests", dependencies: ["MyLibrary"]), ] )
  62. La propuesta 91 Swift 5.3 Soporte para dependencias binarias (SE-0272)

    Package.swift // swift-tools-version:5.6 import PackageDescription let package = Package( name: "MyLibrary", platforms: [ .macOS(.v10_14), .iOS(.v13), .tvOS(.v13) ], products: [ .library( name: "MyLibrary", targets: ["MyLibrary", "SomeRemoteBinaryPackage", "SomeLocalBinaryPackage"]) ], dependencies: [], targets: [ .target( name: "MyLibrary" ), .binaryTarget( name: "SomeRemoteBinaryPackage", url: "https://url/to/some/remote/xcframework.zip", checksum: "The checksum of the ZIP archive that contains the XCFramework." ), .binaryTarget( name: "SomeLocalBinaryPackage", path: "path/to/some.xcframework" ) .testTarget( name: "MyLibraryTests", dependencies: ["MyLibrary"]), ] )
  63. Ruby Inspirado en RubyGems y Bundler 11 Años Primer release:

    1 de Septiembre De 2011 Lenguajes • Objective-C • Swift Distribución • Código fuente • .framework • .a • .xcframework CocoaPods 92
  64. Ruby Inspirado en RubyGems y Bundler 11 Años Primer release:

    1 de Septiembre De 2011 Lenguajes • Objective-C • Swift Distribución • Código fuente • .framework • .a • .xcframework CocoaPods 93
  65. La propuesta • Migrar todas las dependencias de CocoaPods a

    XCFrameworks. • Crear un Swift Package que utilice los mismos archivos XCFramework de CocoaPods. • Finalizar la implementación de VideoDetail. Paso a Paso 98
  66. La propuesta • Se mantiene la estructura del proyecto. •

    Ambas herramientas de gestión de dependencias pueden coexistir. • No implica hacer una migración de todos los módulos. Sus beneficios 99
  67. PodBuilder 102 What is PodBuilder PodBuilder is a complementary tool

    to CocoaPods that allows to prebuild pods into frameworks which can then be included into a project’s repo. Instead of committing pod’s source code you add its compiled counterpart. While there is a size penalty in doing so compilation times will decrease signi fi cantly because pod's source fi les no longer need to be recompiled very often and there's also a lot less for SourceKit to index. Additionally frameworks contain all architecture so they’re ready to be used both on any device and simulator. Depending on the size of the project and number of pods this can translate in a signi fi cant reduction of compilation times (for a large project we designed this tool for we saw a 50% faster compile times, but YMMV).
  68. PodBuilder 103 What is PodBuilder PodBuilder is a complementary tool

    to CocoaPods that allows to prebuild pods into frameworks which can then be included into a project’s repo. Instead of committing pod’s source code you add its compiled counterpart. While there is a size penalty in doing so compilation times will decrease signi fi cantly because pod's source fi les no longer need to be recompiled very often and there's also a lot less for SourceKit to index. Additionally frameworks contain all architecture so they’re ready to be used both on any device and simulator. Depending on the size of the project and number of pods this can translate in a signi fi cant reduction of compilation times (for a large project we designed this tool for we saw a 50% faster compile times, but YMMV).
  69. PodBuilder 104 What is PodBuilder PodBuilder is a complementary tool

    to CocoaPods that allows to prebuild pods into frameworks which can then be included into a project’s repo. Instead of committing pod’s source code you add its compiled counterpart. While there is a size penalty in doing so compilation times will decrease signi fi cantly because pod's source fi les no longer need to be recompiled very often and there's also a lot less for SourceKit to index. Additionally frameworks contain all architecture so they’re ready to be used both on any device and simulator. Depending on the size of the project and number of pods this can translate in a signi fi cant reduction of compilation times (for a large project we designed this tool for we saw a 50% faster compile times, but YMMV).
  70. PodBuilder 105 What is PodBuilder PodBuilder is a complementary tool

    to CocoaPods that allows to prebuild pods into frameworks which can then be included into a project’s repo. Instead of committing pod’s source code you add its compiled counterpart. While there is a size penalty in doing so compilation times will decrease signi fi cantly because pod's source fi les no longer need to be recompiled very often and there's also a lot less for SourceKit to index. Additionally frameworks contain all architecture so they’re ready to be used both on any device and simulator. Depending on the size of the project and number of pods this can translate in a signi fi cant reduction of compilation times (for a large project we designed this tool for we saw a 50% faster compile times, but YMMV).
  71. Integrando PodBuilder 109 $ bundle install Bundle complete! 2 Gemfile

    dependencies, 41 gems now installed. Use `bundle info [gemname]` to see where a bundled gem is installed. . . . $ Gemfile # frozen_string_literal: true source "https://rubygems.org" gem "cocoapods", "1.11.3" gem "pod-builder", "4.4.5" $ bundle exec pod_builder init Bundle complete! 2 Gemfile dependencies, 41 gems now installed. Use `bundle info [gemname]` to see where a bundled gem is installed. . . .
  72. Integrando PodBuilder 110 􀈖 PodBuilder 􀈖 .pod_builder 􀈷 .gitattributes 􀈷

    .gitignore 􀉇 PodBuilder.json Podfile Podfile platform :ios, '15.0' use_frameworks! workspace 'ItunesExample.xcworkspace' def test_pods pod "Quick" pod "Nimble" end def snapshot_test_pods test_pods pod "Nimble-Snapshots" end target 'ItunesExample' do project ‘../ItunesExample.xcodeproj’ pod 'SDWebImageSwiftUI' target 'ItunesExampleTests' do inherit! :search_paths snapshot_test_pods end target 'ItunesExampleUITests' do # Pods for testing end end pre_install do |installer| raise "\n🚨 Do not launch 'pod install' manually, use `pod_builder` instead!\n" if !File.exist?('pod_builder.lock') end
  73. Integrando PodBuilder 111 Podfile platform :ios, '15.0' use_frameworks! workspace 'ItunesExample.xcworkspace'

    def test_pods pod "Quick" pod "Nimble" end def snapshot_test_pods test_pods pod "Nimble-Snapshots" end target 'ItunesExample' do project ‘../ItunesExample.xcodeproj’ pod 'SDWebImageSwiftUI' target 'ItunesExampleTests' do inherit! :search_paths snapshot_test_pods end target 'ItunesExampleUITests' do # Pods for testing end end pre_install do |installer| raise "\n🚨 Do not launch 'pod install' manually, use `pod_builder` instead!\n" if !File.exist?('pod_builder.lock') end Podfile 􀈖 PodBuilder 􀈖 .pod_builder 􀈷 .gitattributes 􀈷 .gitignore 􀉇 PodBuilder.json
  74. Integrando PodBuilder 112 Podfile platform :ios, '15.0' use_frameworks! workspace 'ItunesExample.xcworkspace'

    def test_pods pod "Quick" pod "Nimble" end def snapshot_test_pods test_pods pod "Nimble-Snapshots" end target 'ItunesExample' do project ‘../ItunesExample.xcodeproj’ pod 'SDWebImageSwiftUI' target 'ItunesExampleTests' do inherit! :search_paths snapshot_test_pods end target 'ItunesExampleUITests' do # Pods for testing end end pre_install do |installer| raise "\n🚨 Do not launch 'pod install' manually, use `pod_builder` instead!\n" if !File.exist?('pod_builder.lock') end Podfile 􀈖 PodBuilder 􀈖 .pod_builder 􀈷 .gitattributes 􀈷 .gitignore 􀉇 PodBuilder.json
  75. Integrando PodBuilder 113 Podfile PodBuilder.json { "project_name": "ItunesExample", "spec_overrides": {},

    "skip_licenses": [], "skip_pods": [], "force_prebuild_pods": [], "build_settings": { "ENABLE_BITCODE": “YES", "GCC_OPTIMIZATION_LEVEL": "s", "SWIFT_OPTIMIZATION_LEVEL": "-Osize", "SWIFT_COMPILATION_MODE": "wholemodule", "CODE_SIGN_IDENTITY": "", "CODE_SIGNING_REQUIRED": "NO", "CODE_SIGN_ENTITLEMENTS": "", "CODE_SIGNING_ALLOWED": "NO", "OTHER_SWIFT_FLAGS": "-Xfrontend -module-interface-preserve-types-as-written" }, "build_settings_overrides": {}, "build_system": "Latest", "build_xcframeworks_all": true, "library_evolution_support": true, "license_filename": "Pods-acknowledgements", "restore_enabled": true, "allow_building_development_pods": false, "use_bundler": false, "deterministic_build": false, "build_using_repo_paths": false, "react_native_project": false, "development_team": "" } 􀈖 PodBuilder 􀈖 .pod_builder 􀈷 .gitattributes 􀈷 .gitignore 􀉇 PodBuilder.json
  76. PodBuilder.json { "project_name": "ItunesExample", "spec_overrides": {}, "skip_licenses": [], "skip_pods": [],

    "force_prebuild_pods": [], "build_settings": { "ENABLE_BITCODE": “YES", "GCC_OPTIMIZATION_LEVEL": "s", "SWIFT_OPTIMIZATION_LEVEL": "-Osize", "SWIFT_COMPILATION_MODE": "wholemodule", "CODE_SIGN_IDENTITY": "", "CODE_SIGNING_REQUIRED": "NO", "CODE_SIGN_ENTITLEMENTS": "", "CODE_SIGNING_ALLOWED": "NO", "OTHER_SWIFT_FLAGS": "-Xfrontend -module-interface-preserve-types-as-written" }, "build_settings_overrides": {}, "build_system": "Latest", "build_xcframeworks_all": true, "library_evolution_support": true, "license_filename": "Pods-acknowledgements", "restore_enabled": true, "allow_building_development_pods": false, "use_bundler": false, "deterministic_build": false, "build_using_repo_paths": false, "react_native_project": false, "development_team": "" } Integrando PodBuilder 114 Podfile 􀈖 PodBuilder 􀈖 .pod_builder 􀈷 .gitattributes 􀈷 .gitignore 􀉇 PodBuilder.json
  77. PodBuilder.json { "project_name": "ItunesExample", "spec_overrides": {}, "skip_licenses": [], "skip_pods": [],

    "force_prebuild_pods": [], "build_settings": { "ENABLE_BITCODE": “YES", "GCC_OPTIMIZATION_LEVEL": "s", "SWIFT_OPTIMIZATION_LEVEL": "-Osize", "SWIFT_COMPILATION_MODE": "wholemodule", "CODE_SIGN_IDENTITY": "", "CODE_SIGNING_REQUIRED": "NO", "CODE_SIGN_ENTITLEMENTS": "", "CODE_SIGNING_ALLOWED": "NO", "OTHER_SWIFT_FLAGS": "-Xfrontend -module-interface-preserve-types-as-written" }, "build_settings_overrides": {}, "build_system": "Latest", "build_xcframeworks_all": true, "library_evolution_support": true, "license_filename": "Pods-acknowledgements", "restore_enabled": true, "allow_building_development_pods": false, "use_bundler": false, "deterministic_build": false, "build_using_repo_paths": false, "react_native_project": false, "development_team": "" } Integrando PodBuilder 115 Podfile 􀈖 PodBuilder 􀈖 .pod_builder 􀈷 .gitattributes 􀈷 .gitignore 􀉇 PodBuilder.json
  78. Integrando PodBuilder $ bundle exec pod_builder build_all Build strategy Nimble

    from source (folder hash missing) Nimble-Snapshots from source (folder hash missing) Quick from source (folder hash missing) SDWebImage from source (folder hash missing) SDWebImageSwiftUI from source (folder hash missing) iOSSnapshotTestCase from source (folder hash missing) . . . $ Pod installation complete! There are 6 dependencies from the Podfile and 6 total pods installed. Loading Podfile Checking Podfile.restore Adding inverse dependencies: . . . Preparing build . . . Building xcframeworks for iphoneos Building xcframeworks for iphonesimulator Build completed in 70 seconds . . . Running pod install . . . . . . 🎉 done! 116
  79. Integrando PodBuilder 117 Podfile 􀈖 PodBuilder 􀈖 .pod_builder 􀈷 .gitattributes

    􀈷 .gitignore 􀉇 PodBuilder.json 􀈖 dSYM 􀈖 Prebuilt 􀈖 iOSSnapshotTestCase 􀈖 Nimble 􀈖 Nimble-Snapshots 􀈖 Quick 􀈖 SDWebImage 􀈖 SDWebImageSwiftUI 􀈖 SDWebImageSwiftUI.xcframework SDWebImageSwiftUI.podspec 􀉇 PodBuilder.json
  80. Integrando PodBuilder 118 Podfile 􀈖 PodBuilder 􀈖 .pod_builder 􀈷 .gitattributes

    􀈷 .gitignore 􀉇 PodBuilder.json 􀈖 dSYM 􀈖 Prebuilt 􀈖 iOSSnapshotTestCase 􀈖 Nimble 􀈖 Nimble-Snapshots 􀈖 Quick 􀈖 SDWebImage 􀈖 SDWebImageSwiftUI 􀈖 SDWebImageSwiftUI.xcframework SDWebImageSwiftUI.podspec 􀉇 PodBuilder.json
  81. Integrando PodBuilder 119 Podfile 􀈖 PodBuilder 􀈖 .pod_builder 􀈷 .gitattributes

    􀈷 .gitignore 􀉇 PodBuilder.json 􀈖 dSYM 􀈖 Prebuilt 􀈖 iOSSnapshotTestCase 􀈖 Nimble 􀈖 Nimble-Snapshots 􀈖 Quick 􀈖 SDWebImage 􀈖 SDWebImageSwiftUI 􀈖 SDWebImageSwiftUI.xcframework SDWebImageSwiftUI.podspec 􀉇 PodBuilder.json
  82. Integrando PodBuilder 120 Podfile 􀈖 PodBuilder 􀈖 .pod_builder 􀈷 .gitattributes

    􀈷 .gitignore 􀉇 PodBuilder.json 􀈖 dSYM 􀈖 Prebuilt 􀈖 iOSSnapshotTestCase 􀈖 Nimble 􀈖 Nimble-Snapshots 􀈖 Quick 􀈖 SDWebImage 􀈖 SDWebImageSwiftUI 􀈖 SDWebImageSwiftUI.xcframework SDWebImageSwiftUI.podspec 􀉇 PodBuilder.json
  83. Integrando PodBuilder 121 Podfile 􀈖 PodBuilder 􀈖 .pod_builder 􀈷 .gitattributes

    􀈷 .gitignore 􀉇 PodBuilder.json 􀈖 dSYM 􀈖 Prebuilt 􀈖 iOSSnapshotTestCase 􀈖 Nimble 􀈖 Nimble-Snapshots 􀈖 Quick 􀈖 SDWebImage 􀈖 SDWebImageSwiftUI 􀈖 SDWebImageSwiftUI.xcframework SDWebImageSwiftUI.podspec 􀉇 PodBuilder.json
  84. Integrando PodBuilder 122 Podfile 􀈖 PodBuilder 􀈖 .pod_builder 􀈷 .gitattributes

    􀈷 .gitignore 􀉇 PodBuilder.json 􀈖 dSYM 􀈖 Prebuilt 􀈖 iOSSnapshotTestCase 􀈖 Nimble 􀈖 Nimble-Snapshots 􀈖 Quick 􀈖 SDWebImage 􀈖 SDWebImageSwiftUI 􀈖 SDWebImageSwiftUI.xcframework SDWebImageSwiftUI.podspec 􀉇 PodBuilder.json
  85. Integrando PodBuilder 123 Podfile 􀈖 PodBuilder 􀈖 .pod_builder 􀈷 .gitattributes

    􀈷 .gitignore 􀉇 PodBuilder.json 􀈖 dSYM 􀈖 Prebuilt 􀈖 iOSSnapshotTestCase 􀈖 Nimble 􀈖 Nimble-Snapshots 􀈖 Quick 􀈖 SDWebImage 􀈖 SDWebImageSwiftUI 􀈖 SDWebImageSwiftUI.xcframework SDWebImageSwiftUI.podspec 􀉇 PodBuilder.json
  86. Integrando PodBuilder 124 ItunesExample AudioDetail Networking Search Pods 􀈖 Frameworks

    􀈖 Pods 􀈖 Products 􀈖 Targets Support Files Podfile Podfile (old) platform :ios, '15.0' use_frameworks! workspace 'ItunesExample.xcworkspace' def test_pods pod "Quick" pod "Nimble" end def snapshot_test_pods test_pods pod "Nimble-Snapshots" end target 'ItunesExample' do project 'ItunesExample.xcodeproj' pod 'SDWebImageSwiftUI' target 'ItunesExampleTests' do inherit! :search_paths snapshot_test_pods end target 'ItunesExampleUITests' do # Pods for testing end end
  87. Integrando PodBuilder 125 ItunesExample AudioDetail Networking Search Pods 􀈖 Frameworks

    􀈖 Pods 􀈖 Products 􀈖 Targets Support Files Podfile Podfile (new) # Autogenerated by PodBuilder (https://github.com/Subito-it/PodBuilder) # Any change to this file should be done on PodBuilder/Podfile platform :ios, '15.0' use_frameworks! workspace 'ItunesExample.xcworkspace' def test_pods pod 'Quick', :path => 'PodBuilder/Prebuilt/Quick' # pb<Quick> pod 'Nimble', :path => 'PodBuilder/Prebuilt/Nimble' # pb<Nimble> end def snapshot_test_pods test_pods pod 'iOSSnapshotTestCase', :path => 'PodBuilder/Prebuilt/iOSSnapshotTestCase' # pb<Nimble-Snapshots> pod 'Nimble', :path => 'PodBuilder/Prebuilt/Nimble' # pb<Nimble-Snapshots> pod 'Nimble-Snapshots', :path => 'PodBuilder/Prebuilt/Nimble-Snapshots' # pb<Nimble-Snapshots> end target 'ItunesExample' do project 'ItunesExample.xcodeproj' pod 'SDWebImage', :path => 'PodBuilder/Prebuilt/SDWebImage' # pb<SDWebImageSwiftUI> pod 'SDWebImageSwiftUI', :path => 'PodBuilder/Prebuilt/SDWebImageSwiftUI' # pb<SDWebImageSwiftUI> target 'ItunesExampleTests' do inherit! :search_paths snapshot_test_pods end target 'ItunesExampleUITests' do # Pods for testing end end
  88. Integrando PodBuilder 126 ItunesExample AudioDetail Networking Search Pods 􀈖 Frameworks

    􀈖 Pods 􀈖 Products 􀈖 Targets Support Files Podfile Podfile (new) # Autogenerated by PodBuilder (https://github.com/Subito-it/PodBuilder) # Any change to this file should be done on PodBuilder/Podfile platform :ios, '15.0' use_frameworks! workspace 'ItunesExample.xcworkspace' def test_pods pod 'Quick', :path => 'PodBuilder/Prebuilt/Quick' # pb<Quick> pod 'Nimble', :path => 'PodBuilder/Prebuilt/Nimble' # pb<Nimble> end def snapshot_test_pods test_pods pod 'iOSSnapshotTestCase', :path => 'PodBuilder/Prebuilt/iOSSnapshotTestCase' # pb<Nimble-Snapshots> pod 'Nimble', :path => 'PodBuilder/Prebuilt/Nimble' # pb<Nimble-Snapshots> pod 'Nimble-Snapshots', :path => 'PodBuilder/Prebuilt/Nimble-Snapshots' # pb<Nimble-Snapshots> end target 'ItunesExample' do project 'ItunesExample.xcodeproj' pod 'SDWebImage', :path => 'PodBuilder/Prebuilt/SDWebImage' # pb<SDWebImageSwiftUI> pod 'SDWebImageSwiftUI', :path => 'PodBuilder/Prebuilt/SDWebImageSwiftUI' # pb<SDWebImageSwiftUI> target 'ItunesExampleTests' do inherit! :search_paths snapshot_test_pods end target 'ItunesExampleUITests' do # Pods for testing end end
  89. Integrando PodBuilder 127 ItunesExample AudioDetail Networking Search Pods 􀈖 Frameworks

    􀈖 Pods 􀈖 Products 􀈖 Targets Support Files Podfile Podfile (new) # Autogenerated by PodBuilder (https://github.com/Subito-it/PodBuilder) # Any change to this file should be done on PodBuilder/Podfile platform :ios, '15.0' use_frameworks! workspace 'ItunesExample.xcworkspace' def test_pods pod 'Quick', :path => 'PodBuilder/Prebuilt/Quick' # pb<Quick> pod 'Nimble', :path => 'PodBuilder/Prebuilt/Nimble' # pb<Nimble> end def snapshot_test_pods test_pods pod 'iOSSnapshotTestCase', :path => 'PodBuilder/Prebuilt/iOSSnapshotTestCase' # pb<Nimble-Snapshots> pod 'Nimble', :path => 'PodBuilder/Prebuilt/Nimble' # pb<Nimble-Snapshots> pod 'Nimble-Snapshots', :path => 'PodBuilder/Prebuilt/Nimble-Snapshots' # pb<Nimble-Snapshots> end target 'ItunesExample' do project 'ItunesExample.xcodeproj' pod 'SDWebImage', :path => 'PodBuilder/Prebuilt/SDWebImage' # pb<SDWebImageSwiftUI> pod 'SDWebImageSwiftUI', :path => 'PodBuilder/Prebuilt/SDWebImageSwiftUI' # pb<SDWebImageSwiftUI> target 'ItunesExampleTests' do inherit! :search_paths snapshot_test_pods end target 'ItunesExampleUITests' do # Pods for testing end end
  90. Integrando PodBuilder 128 ItunesExample AudioDetail Networking Search Pods 􀈖 Frameworks

    􀈖 Pods 􀈖 Products 􀈖 Targets Support Files Podfile Podfile (new) # Autogenerated by PodBuilder (https://github.com/Subito-it/PodBuilder) # Any change to this file should be done on PodBuilder/Podfile platform :ios, '15.0' use_frameworks! workspace 'ItunesExample.xcworkspace' def test_pods pod 'Quick', :path => 'PodBuilder/Prebuilt/Quick' # pb<Quick> pod 'Nimble', :path => 'PodBuilder/Prebuilt/Nimble' # pb<Nimble> end def snapshot_test_pods test_pods pod 'iOSSnapshotTestCase', :path => 'PodBuilder/Prebuilt/iOSSnapshotTestCase' # pb<Nimble-Snapshots> pod 'Nimble', :path => 'PodBuilder/Prebuilt/Nimble' # pb<Nimble-Snapshots> pod 'Nimble-Snapshots', :path => 'PodBuilder/Prebuilt/Nimble-Snapshots' # pb<Nimble-Snapshots> end target 'ItunesExample' do project 'ItunesExample.xcodeproj' pod 'SDWebImage', :path => 'PodBuilder/Prebuilt/SDWebImage' # pb<SDWebImageSwiftUI> pod 'SDWebImageSwiftUI', :path => 'PodBuilder/Prebuilt/SDWebImageSwiftUI' # pb<SDWebImageSwiftUI> target 'ItunesExampleTests' do inherit! :search_paths snapshot_test_pods end target 'ItunesExampleUITests' do # Pods for testing end end
  91. Swift Package con dependencias locales 131 Package.swift // swift-tools-version: 5.6

    import PackageDescription let package = Package( name: "Dependencies", products: [ .library( name: "Dependencies", targets: ["Dependencies"] ), .library( name: "iOSSnapshotTestCase", targets: ["FBSnapshotTestCase"] ), .library( name: "Nimble", targets: ["Nimble"] ), .library( name: "Nimble-Snapshots", targets: ["Nimble_Snapshots"] ), .library( name: "Quick", targets: ["Quick"] ), .library( name: "SDWebImage", targets: ["SDWebImage"] ), .library( name: "SDWebImageSwiftUI", targets: ["SDWebImageSwiftUI"] ), ], dependencies: [], targets: [ .target( name: "Dependencies", AudioDetail Networking Search Pods ItunesExample 􀐛 VideoDetail 􀐛 Dependencies 􀉚 README 􀫊 Package 􀣎 Sources 􀈖 Prebuilt 􀈖 iOSSnapshotTestCase 􀈖 Nimble 􀈖 Nimble-Snapshots 􀈖 Quick 􀈖 SDWebImage 􀈖 SDWebImageSwiftUI 􀈖 PodBuilder
  92. Swift Package con dependencias locales 132 Package.swift .library( name: "Nimble-Snapshots",

    targets: ["Nimble_Snapshots"] ), .library( name: "Quick", targets: ["Quick"] ), .library( name: "SDWebImage", targets: ["SDWebImage"] ), .library( name: "SDWebImageSwiftUI", targets: ["SDWebImageSwiftUI"] ), ], dependencies: [], targets: [ .target( name: "Dependencies", dependencies: [] ), .binaryTarget(name: "FBSnapshotTestCase", path: "../PodBuilder/Prebuilt/iOSSnapshotTestCase/FBSnapshotTestCase.xcframework"), .binaryTarget(name: "Nimble", path: "../PodBuilder/Prebuilt/Nimble/Nimble.xcframework"), .binaryTarget(name: "Nimble_Snapshots", path: "../PodBuilder/Prebuilt/Nimble-Snapshots/Nimble_Snapshots.xcframework"), .binaryTarget(name: "Quick", path: "../PodBuilder/Prebuilt/Quick/Quick.xcframework"), .binaryTarget(name: "SDWebImage", path: "../PodBuilder/Prebuilt/SDWebImage/SDWebImage.xcframework"), .binaryTarget(name: "SDWebImageSwiftUI", path: "../PodBuilder/Prebuilt/SDWebImageSwiftUI/SDWebImageSwiftUI.xcframework"), ] ) AudioDetail Networking Search Pods ItunesExample 􀐛 VideoDetail 􀐛 Dependencies 􀉚 README 􀫊 Package 􀣎 Sources 􀈖 Prebuilt 􀈖 iOSSnapshotTestCase 􀈖 Nimble 􀈖 Nimble-Snapshots 􀈖 Quick 􀈖 SDWebImage 􀈖 SDWebImageSwiftUI 􀈖 PodBuilder
  93. Swift Package con dependencias locales 133 Package.swift .library( name: "Nimble-Snapshots",

    targets: ["Nimble_Snapshots"] ), .library( name: "Quick", targets: ["Quick"] ), .library( name: "SDWebImage", targets: ["SDWebImage"] ), .library( name: "SDWebImageSwiftUI", targets: ["SDWebImageSwiftUI"] ), ], dependencies: [], targets: [ .target( name: "Dependencies", dependencies: [] ), .binaryTarget(name: "FBSnapshotTestCase", path: "../PodBuilder/Prebuilt/iOSSnapshotTestCase/FBSnapshotTestCase.xcframework"), .binaryTarget(name: "Nimble", path: "../PodBuilder/Prebuilt/Nimble/Nimble.xcframework"), .binaryTarget(name: "Nimble_Snapshots", path: "../PodBuilder/Prebuilt/Nimble-Snapshots/Nimble_Snapshots.xcframework"), .binaryTarget(name: "Quick", path: "../PodBuilder/Prebuilt/Quick/Quick.xcframework"), .binaryTarget(name: "SDWebImage", path: "../PodBuilder/Prebuilt/SDWebImage/SDWebImage.xcframework"), .binaryTarget(name: "SDWebImageSwiftUI", path: "../PodBuilder/Prebuilt/SDWebImageSwiftUI/SDWebImageSwiftUI.xcframework"), ] ) AudioDetail Networking Search Pods ItunesExample 􀐛 VideoDetail 􀐛 Dependencies 􀉚 README 􀫊 Package 􀣎 Sources 􀈖 Prebuilt 􀈖 iOSSnapshotTestCase 􀈖 Nimble 􀈖 Nimble-Snapshots 􀈖 Quick 􀈖 SDWebImage 􀈖 SDWebImageSwiftUI 􀈖 PodBuilder
  94. Swift Package con dependencias locales 134 Package.swift .library( name: "Nimble-Snapshots",

    targets: ["Nimble_Snapshots"] ), .library( name: "Quick", targets: ["Quick"] ), .library( name: "SDWebImage", targets: ["SDWebImage"] ), .library( name: "SDWebImageSwiftUI", targets: ["SDWebImageSwiftUI"] ), ], dependencies: [], targets: [ .target( name: "Dependencies", dependencies: [] ), .binaryTarget(name: "FBSnapshotTestCase", path: "../PodBuilder/Prebuilt/iOSSnapshotTestCase/FBSnapshotTestCase.xcframework"), .binaryTarget(name: "Nimble", path: "../PodBuilder/Prebuilt/Nimble/Nimble.xcframework"), .binaryTarget(name: "Nimble_Snapshots", path: "../PodBuilder/Prebuilt/Nimble-Snapshots/Nimble_Snapshots.xcframework"), .binaryTarget(name: "Quick", path: "../PodBuilder/Prebuilt/Quick/Quick.xcframework"), .binaryTarget(name: "SDWebImage", path: "../PodBuilder/Prebuilt/SDWebImage/SDWebImage.xcframework"), .binaryTarget(name: "SDWebImageSwiftUI", path: "../PodBuilder/Prebuilt/SDWebImageSwiftUI/SDWebImageSwiftUI.xcframework"), ] ) AudioDetail Networking Search Pods ItunesExample 􀐛 VideoDetail 􀐛 Dependencies 􀉚 README 􀫊 Package 􀣎 Sources 􀈖 Prebuilt 􀈖 iOSSnapshotTestCase 􀈖 Nimble 􀈖 Nimble-Snapshots 􀈖 Quick 􀈖 SDWebImage 􀈖 SDWebImageSwiftUI 􀈖 PodBuilder
  95. Swift Package con dependencias locales 135 Package.swift .library( name: "Nimble-Snapshots",

    targets: ["Nimble_Snapshots"] ), .library( name: "Quick", targets: ["Quick"] ), .library( name: "SDWebImage", targets: ["SDWebImage"] ), .library( name: "SDWebImageSwiftUI", targets: ["SDWebImageSwiftUI"] ), ], dependencies: [], targets: [ .target( name: "Dependencies", dependencies: [] ), .binaryTarget(name: "FBSnapshotTestCase", path: "../PodBuilder/Prebuilt/iOSSnapshotTestCase/FBSnapshotTestCase.xcframework"), .binaryTarget(name: "Nimble", path: "../PodBuilder/Prebuilt/Nimble/Nimble.xcframework"), .binaryTarget(name: "Nimble_Snapshots", path: "../PodBuilder/Prebuilt/Nimble-Snapshots/Nimble_Snapshots.xcframework"), .binaryTarget(name: "Quick", path: "../PodBuilder/Prebuilt/Quick/Quick.xcframework"), .binaryTarget(name: "SDWebImage", path: "../PodBuilder/Prebuilt/SDWebImage/SDWebImage.xcframework"), .binaryTarget(name: "SDWebImageSwiftUI", path: "../PodBuilder/Prebuilt/SDWebImageSwiftUI/SDWebImageSwiftUI.xcframework"), ] ) AudioDetail Networking Search Pods ItunesExample 􀐛 VideoDetail 􀐛 Dependencies 􀉚 README 􀫊 Package 􀣎 Sources 􀈖 Prebuilt 􀈖 iOSSnapshotTestCase 􀈖 Nimble 􀈖 Nimble-Snapshots 􀈖 Quick 􀈖 SDWebImage 􀈖 SDWebImageSwiftUI 􀈖 PodBuilder
  96. Swift Package con dependencias locales 136 Package.swift .library( name: "Nimble-Snapshots",

    targets: ["Nimble_Snapshots"] ), .library( name: "Quick", targets: ["Quick"] ), .library( name: "SDWebImage", targets: ["SDWebImage"] ), .library( name: "SDWebImageSwiftUI", targets: ["SDWebImageSwiftUI"] ), ], dependencies: [], targets: [ .target( name: "Dependencies", dependencies: [] ), .binaryTarget(name: "FBSnapshotTestCase", path: "../PodBuilder/Prebuilt/iOSSnapshotTestCase/FBSnapshotTestCase.xcframework"), .binaryTarget(name: "Nimble", path: "../PodBuilder/Prebuilt/Nimble/Nimble.xcframework"), .binaryTarget(name: "Nimble_Snapshots", path: "../PodBuilder/Prebuilt/Nimble-Snapshots/Nimble_Snapshots.xcframework"), .binaryTarget(name: "Quick", path: "../PodBuilder/Prebuilt/Quick/Quick.xcframework"), .binaryTarget(name: "SDWebImage", path: "../PodBuilder/Prebuilt/SDWebImage/SDWebImage.xcframework"), .binaryTarget(name: "SDWebImageSwiftUI", path: "../PodBuilder/Prebuilt/SDWebImageSwiftUI/SDWebImageSwiftUI.xcframework"), ] ) AudioDetail Networking Search Pods ItunesExample 􀐛 VideoDetail 􀐛 Dependencies 􀉚 README 􀫊 Package 􀣎 Sources 􀈖 Prebuilt 􀈖 iOSSnapshotTestCase 􀈖 Nimble 􀈖 Nimble-Snapshots 􀈖 Quick 􀈖 SDWebImage 􀈖 SDWebImageSwiftUI 􀈖 PodBuilder
  97. Integrando dependencias 138 AudioDetail Networking Search Pods ItunesExample 􀐛 VideoDetail

    􀉚 README 􀫊 Package 􀣎 Sources 􀣎 Tests Package.swift (old) // swift-tools-version: 5.6 import PackageDescription let package = Package( name: "VideoDetail", platforms: [ .iOS(.v15), ], products: [ .library( name: "VideoDetail", type: .dynamic, targets: ["VideoDetail"] ), ], dependencies: [ .package(url: "https://github.com/SDWebImage/SDWebImageSwiftUI.git", from: "2.0.0"), .package(url: "https://github.com/Quick/Quick.git", from: "5.0.0"), .package(url: "https://github.com/Quick/Nimble.git", from: "10.0.0"), .package(url: "https://github.com/ashfurrow/Nimble-Snapshots.git", from: "9.0.0"), ], targets: [ .target( name: "VideoDetail", dependencies: [ "SDWebImageSwiftUI", ] ), .testTarget( name: "VideoDetailTests", dependencies: [ "VideoDetail", "Quick", "Nimble", "Nimble-Snapshots", ] ), ] ) 􀐛 Dependencies
  98. Integrando dependencias 139 AudioDetail Networking Search Pods ItunesExample 􀐛 VideoDetail

    􀉚 README 􀫊 Package 􀣎 Sources 􀣎 Tests Package.swift (old) // swift-tools-version: 5.6 import PackageDescription let package = Package( name: "VideoDetail", platforms: [ .iOS(.v15), ], products: [ .library( name: "VideoDetail", type: .dynamic, targets: ["VideoDetail"] ), ], dependencies: [ .package(url: "https://github.com/SDWebImage/SDWebImageSwiftUI.git", from: "2.0.0"), .package(url: "https://github.com/Quick/Quick.git", from: "5.0.0"), .package(url: "https://github.com/Quick/Nimble.git", from: "10.0.0"), .package(url: "https://github.com/ashfurrow/Nimble-Snapshots.git", from: "9.0.0"), ], targets: [ .target( name: "VideoDetail", dependencies: [ "SDWebImageSwiftUI", ] ), .testTarget( name: "VideoDetailTests", dependencies: [ "VideoDetail", "Quick", "Nimble", "Nimble-Snapshots", ] ), ] ) 􀐛 Dependencies
  99. Integrando dependencias 140 AudioDetail Networking Search Pods ItunesExample 􀐛 VideoDetail

    􀉚 README 􀫊 Package 􀣎 Sources 􀣎 Tests Package.swift (New) // swift-tools-version: 5.6 import PackageDescription let package = Package( name: "VideoDetail", platforms: [ .iOS(.v15), ], products: [ .library( name: "VideoDetail", type: .dynamic, targets: ["VideoDetail"] ), ], dependencies: [ .package(path: "../Dependencies"), ], targets: [ .target( name: "VideoDetail", dependencies: [ .product(name: "SDWebImageSwiftUI", package: "Dependencies"), .product(name: "SDWebImage", package: "Dependencies"), ] ), .testTarget( name: "VideoDetailTests", dependencies: [ "VideoDetail", .product(name: "Quick", package: "Dependencies"), .product(name: "Nimble", package: "Dependencies"), .product(name: "Nimble-Snapshots", package: "Dependencies"), ] ), ] ) 􀐛 Dependencies
  100. Integrando dependencias 141 AudioDetail Networking Search Pods ItunesExample 􀐛 VideoDetail

    􀉚 README 􀫊 Package 􀣎 Sources 􀣎 Tests Package.swift (New) // swift-tools-version: 5.6 import PackageDescription let package = Package( name: "VideoDetail", platforms: [ .iOS(.v15), ], products: [ .library( name: "VideoDetail", type: .dynamic, targets: ["VideoDetail"] ), ], dependencies: [ .package(path: "../Dependencies"), ], targets: [ .target( name: "VideoDetail", dependencies: [ .product(name: "SDWebImageSwiftUI", package: "Dependencies"), .product(name: "SDWebImage", package: "Dependencies"), ] ), .testTarget( name: "VideoDetailTests", dependencies: [ "VideoDetail", .product(name: "Quick", package: "Dependencies"), .product(name: "Nimble", package: "Dependencies"), .product(name: "Nimble-Snapshots", package: "Dependencies"), ] ), ] ) 􀐛 Dependencies
  101. Integrando dependencias 142 AudioDetail Networking Search Pods ItunesExample 􀐛 VideoDetail

    􀉚 README 􀫊 Package 􀣎 Sources 􀣎 Tests Package.swift (New) // swift-tools-version: 5.6 import PackageDescription let package = Package( name: "VideoDetail", platforms: [ .iOS(.v15), ], products: [ .library( name: "VideoDetail", type: .dynamic, targets: ["VideoDetail"] ), ], dependencies: [ .package(path: "../Dependencies"), ], targets: [ .target( name: "VideoDetail", dependencies: [ .product(name: "SDWebImageSwiftUI", package: "Dependencies"), .product(name: "SDWebImage", package: "Dependencies"), ] ), .testTarget( name: "VideoDetailTests", dependencies: [ "VideoDetail", .product(name: "Quick", package: "Dependencies"), .product(name: "Nimble", package: "Dependencies"), .product(name: "Nimble-Snapshots", package: "Dependencies"), ] ), ] ) 􀐛 Dependencies
  102. Integrando dependencias 143 AudioDetail Networking Search Pods ItunesExample 􀐛 VideoDetail

    􀉚 README 􀫊 Package 􀣎 Sources 􀣎 Tests Package.swift (New) // swift-tools-version: 5.6 import PackageDescription let package = Package( name: "VideoDetail", platforms: [ .iOS(.v15), ], products: [ .library( name: "VideoDetail", type: .dynamic, targets: ["VideoDetail"] ), ], dependencies: [ .package(path: "../Dependencies"), ], targets: [ .target( name: "VideoDetail", dependencies: [ .product(name: "SDWebImageSwiftUI", package: "Dependencies"), .product(name: "SDWebImage", package: "Dependencies"), ] ), .testTarget( name: "VideoDetailTests", dependencies: [ "VideoDetail", .product(name: "Quick", package: "Dependencies"), .product(name: "Nimble", package: "Dependencies"), .product(name: "Nimble-Snapshots", package: "Dependencies"), ] ), ] ) 􀐛 Dependencies
  103. Conclusiones y Tips • El proceso de hacer convivir dependencias

    de CocoaPods y SPM no es trivial. • Usar XCFrameworks para todo tiene beneficios pero también quita visibilidad sobre el código fuente de las bibliotecas. • Integrar PodBuilder no siempre es sencillo. A veces se debe iterar mucho con la herramienta. 146