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 |