Skip to content

Instantly share code, notes, and snippets.

View laevandus's full-sized avatar

Toomas Vahter laevandus

View GitHub Profile
extension Publisher where Self.Failure == Never {
public func notifyObjectWillChange(_ objectWillChange: ObservableObjectPublisher) -> AnyCancellable {
return self.sink { _ in
objectWillChange.send()
}
}
}
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)
struct InputView: View {
let title: String
var placeholder: String = ""
let value: Binding<String>
var body: some View {
VStack {
HStack {
Text(title)
.font(.subheadline)
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)
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()
// MARK: View
struct PackageCombineModelView: View {
@StateObject var viewModel: ViewModel
var body: some View {
Form {
TextField("First name", text: $viewModel.firstName)
Text(viewModel.modelDescription)
}
// MARK: View
struct PackageKVOModelView: View {
@StateObject var viewModel: ViewModel
var body: some View {
Form {
TextField("First name", text: $viewModel.firstName)
Text(viewModel.modelDescription)
}
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
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
}
extension CGSize {
enum Aspect {
case portrait, landscape, square
}
var aspect: Aspect {
switch width / height {
case 1.0:
return .square
case 1.0...:
return .landscape