Post

Replies

Boosts

Views

Activity

A syntax error I'm not understanding...
I'm defining a typealias for a set, and then creating an extension for the new typealias. When I do this, I'm getting an odd syntax error. Any/all guidance appreciated. typealias IntSet = Set<Int> extension IntSet { func aFunction() -> Set<String> { let array: [String] = self.map { "\($0)" } return Set(array) } } At the return line, I get the following syntax error: Cannot convert return expression of type 'Set<Int>' to return type 'Set<String>' Even if I replace the return line with the following, I get the same compile error return Set("array")
3
0
707
May ’24
Looking to use @AppStorage, but avoid depending on UserDefaults.standard
I am using @AppStorage in a model object (see code below that works as expected). class ModelObject { static let shared = ModelObject() @AppStorage("enhanced") var scriptPickers: Bool = true var defaultDependentValue: String { scriptPickers ? "Enhanced" : "NOT enhanced" } } struct ContentView: View { @AppStorage("enhanced") var scriptPickers: Bool = true var body: some View { VStack { Toggle(isOn: $scriptPickers, label: { Text("userDefault val") }) Text("value: \(ModelObject.shared.defaultDependentValue)") } } } Now I want to test my model object in a way that will allow me to use a mock instance of UserDefaults, but am having trouble with the syntax. I tried adding a userDefaults var, and referring to the var in the @AppStorage class ModelObject { static let shared = ModelObject() let userDefaults: UserDefaults init(userDefaults: UserDefaults = .standard) { self.userDefaults = userDefaults } @AppStorage("enhanced", store: userDefaults) var scriptPickers: Bool = true var defaultDependentValue: String { scriptPickers ? "Enhanced" : "NOT enhanced" } } However I can't find a way to avoid the syntax error this generates: Cannot use instance member 'userDefaults' within property initializer; property initializers run before 'self' is available Any guidance on how I might be able to: continue using @AppStorage be able to test my class in a way that doesn't force me to use UserDefaults.standard thanks, in advance, Mike
2
0
514
May ’24
Unexpected behaviour when attempting to decode enum keys from a JSON dictionary
This first code works fine decoding json. static let localizationsDictText = """ { "en" : { "string" : "Cat" }, "fr" : { "string" : "Chat"} } """ struct Localization: Codable, Equatable { let string: String } typealias LocalizationsDict = [String: Localization] func testExample() throws { let text = Self.localizationsDictText let data = text.data(using: .utf8, allowLossyConversion: false) let localizationsDict = try JSONDecoder().decode(LocalizationsDict.self, from: data!) XCTAssertEqual(localizationsDict.keys.count, 2) } But then I try to create a modified version of the above, only changing the type of the LocalizationsDict key from String to an enum: enum Language: String, CaseIterable, Codable { case en = "en" case fr = "fr" } typealias LocalizationsDict2 = [Language: Localization] func testExample2() throws { let text = Self.localizationsDictText let data = text.data(using: .utf8, allowLossyConversion: false) let localizationsDict = try JSONDecoder().decode(LocalizationsDict2.self, from: data!) XCTAssertEqual(localizationsDict.keys.count, 2) } and the JSONDecoder line throws an exception: testExample2(): failed: caught error: "typeMismatch(Swift.Array<Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array<Any> but found a dictionary instead.", underlyingError: nil))" Any suggestions as to why switching from [String: Localization] to [Language: Localization] might cause JSONDecode() to treat it like an array? Thanks in advance for any guidance.
2
0
643
Mar ’24
I want to move a CoreImage task to the background...
It feels like this should be easy, but I'm having conceptual problems about how to do this. Any help would be appreciated. I have a sample app below that works exactly as expected. I'm able to use the Slider and Stepper to generate inputs to a function that uses CoreImage filters to manipulate my input image. This all works as expected, but it's doing some O(n) CI work on the main thread, and I want to move it to a background thread. I'm pretty sure this can be done using combine, here is the pseudo code I imagine would work for me: func doStuff() { // subscribe to options changes // .receive on background thread // .debounce // .map { model.inputImage.combine(options: $0) // return an object on the main thread. // update an @Published property? } Below is the POC code for my project. Any guidance as to where I should use combine to do this would be greatly appreciate. (Also, please let me know if you think combine is not the best way to tackle this. I'd be open to alternative implementations.) struct ContentView: View { @State private var options = CombineOptions.basic @ObservedObject var model = Model() var body: some View { VStack { Image(uiImage: enhancedImage) .resizable() .aspectRatio(contentMode: .fit) Slider(value: $options.scale) Stepper(value: $options.numberOfImages, label: { Text("\(options.numberOfImages)")}) } } private var enhancedImage: UIImage { return model.inputImage.combine(options: options) } } class Model: ObservableObject { let inputImage: UIImage = UIImage.init(named: "IMG_4097")! } struct CombineOptions: Codable, Equatable { static let basic: CombineOptions = .init(scale: 0.3, numberOfImages: 10) var scale: Double var numberOfImages: Int }
1
0
871
Jan ’24
UIHostingController question...
I have a SwiftUI view that works as expected in a full SwiftUI context. But I now need to use it in a UIViewController. It mostly works, but I'm trying to expose an @State var out to the viewController, and it only ever returns the initial value. Any guidance for how best to pass out this @State var? I could make it be a binding, but in my pure SwiftUI code, it works fine as @State (ie EditorView's container view does not need to know about sliderVal) thanks, in advance, for any suggestions import SwiftUI import UIKit class ViewController: UIViewController { var host: UIHostingController<EditorView>? override func viewDidLoad() { super.viewDidLoad() host = .init(rootView: EditorView()) guard let host = host else { return } addChild(host) host.view.translatesAutoresizingMaskIntoConstraints = false view.addSubview(host.view) host.didMove(toParent: self) } @IBAction func helloTapped(sender: UIButton) { guard let sliderValue = host?.rootView.sliderVal else { return } print("UIKit sliderValue: \(sliderValue)") } } struct EditorView: View { @State var sliderVal: Double init(sliderVal: Double? = nil) { _sliderVal = State(initialValue: sliderVal ?? 7) } var body: some View { VStack { Slider(value: $sliderVal, in: 1...10) Text("sliderVal: \(sliderVal)") } } } (NOTE: in order to see this code snippet in action you will need to create a button in the storyboard and link it to helloTapped)
2
0
1.2k
Jan ’24
Should Photo Extensions work in iOS simulators?
When I: open an existing project create a new PhotoExtensions target run the new target in an iOS simulator (eg iPhone 15, iOS 17.0) Select photos as the app to run Open a photo Tap the ... button at the top right I see: Copy, Duplicate, Hide, etc. But I do not see my new Extension. Is there something else I need to be doing in order to see my new Extension in 'action'?
1
0
715
Jan ’24
Problems in the iOS Simulator's Photos app?
When I: open a simulator (eg iPhone 15, iOS 17.0) open the Photos app tap on an image (either one that comes included, or something I've saved to PhotoRoll) tap Edit I see the typical Photos Edit view with two key differences. the image is not visible, the middle of the view is all black there are now Cancel/Done/Dismiss buttons. I need to force quit to get back to the Springboard (Is that still the correct term?) Am I doing something wrong, or should the simulator's Photo's app be providing a better edit experience?
1
0
725
Jan ’24
Can I put a swiftUI container's content in a func/var/let?
I'm trying to find a syntactically correct way to put the contents of a Container in a separate variable (or function). Can anyone steer me in the right direction? thanks, in advance, mike struct ContentView: View { var body: some View { VStack(content: containerContent) .padding() } var containerContent: () -> Content { return { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text("Hello, world!") } } }
1
0
527
Nov ’23
Unable to deploy CloudKit Dev Schema to production
This will be the initial production schema for this container. When I attempt to start deployment, the Confirm Deployment dialog appears and spins for a while. It then reports "There was a problem loading the environment's status." When I clear the error the Confirm Deployment dialog reports: "No Changes to Deploy" "The schema in the development environment is the same as production." (spoiler, they are not the same) Any suggestions?
0
0
591
May ’21
In SwiftUI I would like to declare an @ObservedObject var with a type defined in a protocol...
See sample code below... Basically it's a galleryView with a dataSource that can add/remove items dynamically. It works as expected when GalleryView's dataSource variable has a type (that conforms to ObservableObject) However when I change dataSource's type to be a protocol, I can't seem to get my code to compile. Any guidance on how to use a protocol in GalleryView, and continue to keep the UI updating when the model object's item list changes? thanks! Mike protocol GalleryDataSource: ObservableObject {     var itemCount: Int { get }     func item(for index: Int) - String } class GalleryModel: ObservableObject {     static let test1: GalleryModel = GalleryModel(items: ["A","B","C"])     @Published var items: [String]     init(items: [String]) {         self.items = items     } } extension GalleryModel: GalleryDataSource {     var itemCount: Int {         return items.count     }     func item(for index: Int) - String {         return items[index]     } } struct ContentView: View {     var model: GalleryModel = GalleryModel.test1     var body: some View {         VStack {             GalleryView(dataSource: model)             Button("Add Item") {                 model.items.append("\(model.items.count)")             }         }     } } struct GalleryView: View {     @ObservedObject var dataSource: GalleryModel //GalleryDataSource     var body: some View {         ScrollView(.horizontal, content: {             HStack {                 ForEach(0..self.dataSource.itemCount, id:\.self) { index in                     Text(dataSource.item(for: index))                         .padding()                 }             }         })     } }
1
0
4.5k
May ’21
Not sure how to add Prev/Next buttons in my SwiftUI List's Detail view.
I have a SwiftUI app with a List displaying an array of model objects. When the user taps a list item we see its detail view. I want to add previous and next buttons to my detail view, but I'm not sure what needs to happen when previous/next are tapped. (see code below for what I'm looking to do) My first thought is to make the model variable in the DetailView be a binding, but I'm not sure how this would tie in with the NavigationLink 'stuff' any/all suggestions appreciated. thanks! class Model: Identifiable {     var modelValue: Int     init(modelValue: Int) {         self.modelValue = modelValue     }     static let testData = [Model(modelValue: 3), Model(modelValue: 7), Model(modelValue: 31)] } class ModelManager {     static let shared = ModelManager()     let modelList = Model.testData     func previous(for model: Model) - Model? {         if let index = modelList.firstIndex(where: {$0.modelValue == model.modelValue}) {             if index 0 {                 return modelList[index - 1]             }         }         return nil     }     func next(for model: Model) - Model? {         if let index = modelList.firstIndex(where: {$0.modelValue == model.modelValue}) {             if index modelList.count - 1  {                 return modelList[index + 1]             }         }         return nil     } } struct ContentView: View {     let manager:ModelManager = ModelManager.shared     var body: some View {         NavigationView {             List(manager.modelList) { object in                 NavigationLink(                     destination: DetailView(model: object, previous: manager.previous(for: object), next: manager.next(for: object)),                     label: {                         Text("fred \(object.modelValue)")                     })             }         }     } } struct DetailView: View {     var model: Model     var previous: Model?     var next: Model?     var body: some View {         VStack {             HStack {                 if previous != nil {                     Button("Previous") {                         // goto previous                     }                 }                 Spacer()                 if next != nil {                     Button("Next") {                         // goto next                     }                 }             }             Text("value: \(model.modelValue)")             Spacer()         }     } }
1
0
1.5k
Mar ’21
Having problems with a SwiftUI checkbox binding I'm implementing...
Hello folks, I'm attempting to implement some swiftUI UI code to support filtering of a list. One part of the filtering involves displaying one checkbox for each case/value of an enum (TangleType below) TangleFilter is a model class that includes an array of TangleTypeFilter objects (each owning a single bool value and a binding) Expected behaviour: when user taps a checkbox, the checkbox toggles the display and the filter model object toggles its value. Actual behaviour: the model is updating appropriately, however the UI is not updating. (the single filter below the list does in fact behave correctly any and all guidance greatly appreciated Mike struct ContentView: View {     @State var isChecked: Bool = false     @ObservedObject var filter = TangleFilter()     @ObservedObject var singleFilter: TangleTypeFilter     init() {         self.singleFilter = TangleTypeFilter(tangleType: .grid)     }     var body: some View {         VStack{             List(filter.tangleTypes, id: \.self) {tangleTypeFilter in                 HStack {                     // when uncommented the following line returns the following                     // compile error:                     // Use of unresolved identifier '$tangleTypeFilter' //                    CheckBox(isChecked: $tangleTypeFilter.isChecked)                     CheckBox(isChecked: tangleTypeFilter.binding)                     Text("checked? \(tangleTypeFilter.isChecked.description)")                 }             }             CheckBox(isChecked: $singleFilter.isChecked)         }     } } struct CheckBox: View {     @Binding var isChecked: Bool {         didSet {             print("setting isChecked: \(isChecked)")         }     }     var imageName: String {         return isChecked ? "checkmark.square" : "square"     }     var body: some View {         Button(action: {             self.isChecked.toggle()         }) {             Image(systemName: self.imageName)         }     } } enum TangleType: String, Codable, CaseIterable {     static let filterArray: [TangleTypeFilter] = {         var result: [TangleTypeFilter] = []         for tangleType in TangleType.allCases {             result.append(TangleTypeFilter(tangleType: tangleType))         }         return result     }()     case grid     case row } class TangleFilter: ObservableObject {     @Published var tangleTypes: [TangleTypeFilter] = TangleType.filterArray } class TangleTypeFilter: ObservableObject {     var tangleType: TangleType     @Published var isChecked: Bool     lazy var binding: Binding<Bool> = Binding(get: {         return self.isChecked     }, set: {         self.isChecked = $0     })     init(tangleType: TangleType) {         self.tangleType = tangleType         self.isChecked = false     } } extension TangleTypeFilter: Hashable {     static func == (lhs: TangleTypeFilter, rhs: TangleTypeFilter) -> Bool {         return lhs.tangleType == rhs.tangleType     }     func hash(into hasher: inout Hasher) {         hasher.combine(tangleType)     } }
6
1
2.7k
Jan ’21
A potentially dumb questions about swift (and dateFormatters)
I seem to recall hearing that DateFormatters are (or were) expensive to instantiate. With this in mind, I tried a small experiment with the following code: class MyClass { &#9;&#9;static let df = DrawingCellView.dateFormatter     static var dateFormatter: DateFormatter {         let result = DateFormatter()         result.dateFormat = "yyyy-MM-dd"         return result     } &#9;&#9;func dateText() -> String { &#9;&#9;&#9;&#9;return MyClass.dateFormatter.string(from: Date()) &#9;&#9;} When I put a breakpoint in the dateFormatter code, it fires each time I use it. However if I instead use df, the breakpoint only fires once. Does this make sense? If so, is this the recommended way to construct a runOnce static constant declaration/assignment? thanks! Mike
2
0
648
Jan ’21
SwiftUI; Can I use abstraction here?
I'm building a swiftUI app. On smaller iOS devices, I want to show a button that will open a webView. on larger devices, I want to show the webView in the current hierarchy. The following code:     func showNotesView() -> some View {         if horizontalSizeClass == .compact {             return NavigationLink(destination: webView) {                 Text("Episode Notes")             }         }             return webView     } generates a compile error at line1 Function declares an opaque return type, but the return statements in its body do not have matching underlying types 1. Return statement has underlying type 'NavigationLink<Text, some View>' 2. Return statement has underlying type 'some View'
1
1
1.9k
Oct ’20
how to notify swiftUI View when source of truth has changed
I have a somewhat obscure source of truth related to a like/favourite button. When a user taps the button, the model object is added to the favourites list. When they tap again, the model object is removed from the list. The actual button is wired to a custom binding, however it is not getting re-drawn when I add/remove items from the favourites list. What do I need to do to let the button know it needs to redraw? thanks struct Model: Equatable {     var name: String     var isFavourite: Bool {         Favourites.shared.includes(model: self)} } class Favourites {     static let shared = Favourites()     var favList: [Model] = []     func add(model: Model) {         favList.append(model)     }     func remove(model: Model) {         if let index = favList.firstIndex(where: {$0 == model}) {             favList.remove(at: index)         }     }     func includes(model: Model) -> Bool {         return favList.firstIndex(where: {$0 == model}) != nil     } } struct ContentView: View {     var model = Model(name: "Andrew")     var favouriteBinding: Binding<Bool> {         Binding<Bool>(             get: {                 return self.model.isFavourite         },             set: {                 if $0 {                     Favourites.shared.add(model: self.model)                 } else {                     Favourites.shared.remove(model: self.model)                 }         })     }     var body: some View {         FavouriteView(isFavourite: favouriteBinding)     } } struct FavouriteView: View {     @Binding var isFavourite: Bool     var body: some View {         Button(action: {             self.isFavourite.toggle()         }) {             Image(systemName: imageName())                 .foregroundColor(Color.yellow)                 .font(Font.system(size: 40))         }     }     func imageName() -> String {         return isFavourite ? "star.fill" : "star"     } }
2
0
2.8k
Oct ’20