View ContentView.swift
extension ContentView { | |
final class ViewModel: ObservableObject { | |
@Published var selectedImage: UIImage? | |
@Published var isPresentingImagePicker = false | |
private(set) var sourceType: ImagePicker.SourceType = .camera | |
func choosePhoto() { | |
sourceType = .photoLibrary | |
isPresentingImagePicker = true | |
} |
View ImagePicker.swift
struct ImagePicker: UIViewControllerRepresentable { | |
typealias UIViewControllerType = UIImagePickerController | |
typealias SourceType = UIImagePickerController.SourceType | |
let sourceType: SourceType | |
let completionHandler: (UIImage?) -> Void | |
func makeUIViewController(context: Context) -> UIImagePickerController { | |
let viewController = UIImagePickerController() | |
viewController.delegate = context.coordinator |
View Publisher.swift
extension Publisher where Self.Failure == Never { | |
public func notifyObjectWillChange(_ objectWillChange: ObservableObjectPublisher) -> AnyCancellable { | |
return self.sink { _ in | |
objectWillChange.send() | |
} | |
} | |
} |
View ViewModel.swift
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) |
View InputView.swift
struct InputView: View { | |
let title: String | |
var placeholder: String = "" | |
let value: Binding<String> | |
var body: some View { | |
VStack { | |
HStack { | |
Text(title) | |
.font(.subheadline) |
View ContentView.swift
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) |
View PackageKVO.swift
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() |
View PackageCombineModelView.swift
// MARK: View | |
struct PackageCombineModelView: View { | |
@StateObject var viewModel: ViewModel | |
var body: some View { | |
Form { | |
TextField("First name", text: $viewModel.firstName) | |
Text(viewModel.modelDescription) | |
} |
View PackageKVOModelView.swift
// MARK: View | |
struct PackageKVOModelView: View { | |
@StateObject var viewModel: ViewModel | |
var body: some View { | |
Form { | |
TextField("First name", text: $viewModel.firstName) | |
Text(viewModel.modelDescription) | |
} |
View ImageScaler.swift
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 |
NewerOlder