This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| extension Publisher where Self.Failure == Never { | |
| public func notifyObjectWillChange(_ objectWillChange: ObservableObjectPublisher) -> AnyCancellable { | |
| return self.sink { _ in | |
| objectWillChange.send() | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| extension ContentView { | |
| final class ViewModel: ObservableObject { | |
| private let package: Package | |
| private var cancellables = [AnyCancellable]() | |
| init(package: Package) { | |
| self.package = package | |
| // Model -> View Model | |
| package.recipient.publisher(for: \.firstName) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| struct InputView: View { | |
| let title: String | |
| var placeholder: String = "" | |
| let value: Binding<String> | |
| var body: some View { | |
| VStack { | |
| HStack { | |
| Text(title) | |
| .font(.subheadline) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| struct ContentView: View { | |
| @StateObject var viewModel = ViewModel(package: .makeExample()) | |
| var body: some View { | |
| ScrollView { | |
| VStack(spacing: 16) { | |
| Text("Recipient") | |
| .font(.headline) | |
| InputView(title: "First name", | |
| value: $viewModel.recipientFirstName) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| final class Package: NSObject { | |
| @objc dynamic var recipient = Person() | |
| @objc dynamic var sender = Person() | |
| @objc dynamic var contents = [PackageContent]() | |
| } | |
| final class Person: NSObject { | |
| @objc dynamic var firstName: String = "" | |
| @objc dynamic var lastName: String = "" | |
| @objc dynamic var postalAddress = CNPostalAddress() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // MARK: View | |
| struct PackageCombineModelView: View { | |
| @StateObject var viewModel: ViewModel | |
| var body: some View { | |
| Form { | |
| TextField("First name", text: $viewModel.firstName) | |
| Text(viewModel.modelDescription) | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // MARK: View | |
| struct PackageKVOModelView: View { | |
| @StateObject var viewModel: ViewModel | |
| var body: some View { | |
| Form { | |
| TextField("First name", text: $viewModel.firstName) | |
| Text(viewModel.modelDescription) | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| struct ImageScaler { | |
| static func scaleToFill(_ image: UIImage, in targetSize: CGSize, from fromRect: CGRect = .zero) -> UIImage { | |
| let rect = fromRect.isEmpty ? CGRect(origin: .zero, size: image.size) : fromRect | |
| let scaledRect = rect.scaled(toFillSize: targetSize) | |
| return scale(image, fromRect: scaledRect, targetSize: targetSize) | |
| } | |
| private static func scale(_ image: UIImage, fromRect: CGRect = .zero, targetSize: CGSize) -> UIImage { | |
| let renderer = UIGraphicsImageRenderer(size: targetSize) | |
| return renderer.image { context in |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| extension CGRect { | |
| func scaled(toFillSize targetSize: CGSize) -> CGRect { | |
| var scaledRect = self | |
| switch (size.aspect, targetSize.aspect) { | |
| case (.portrait, .portrait), (.portrait, .square): | |
| scaledRect.size.height = width / targetSize.aspectRatio | |
| scaledRect.size.width = width | |
| if scaledRect.height > height { | |
| scaledRect.size = size | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| extension CGSize { | |
| enum Aspect { | |
| case portrait, landscape, square | |
| } | |
| var aspect: Aspect { | |
| switch width / height { | |
| case 1.0: | |
| return .square | |
| case 1.0...: | |
| return .landscape |