Post

Replies

Boosts

Views

Activity

Not sure how best to start a network fetch in a specific case in my SwiftUI code
I have a button in my swiftUI view that allows users to open a datePicker and then use the selected date to start a network fetch. The date picker is presented using this code:         .sheet(isPresented: $showDatePicker) {             ModalDatePicker(startDate: self.podcast.earliestDate,                             endDate: self.podcast.latestDate,                             currentDate: self.$datePickerDate,                             isShowing: self.$showDatePicker,                             doneTapped: self.$dateSelected)         } My plan is to use dateSelected to know when the user taps Done rather than cancelling. But I'm not sure where I need to check dateSelected. My first thought was in the body method. if dateSelected { dateSelected = false startFetch() } But that doesn't seem to compile, and frankly feels wrong. I also thought of doing this in ModalDatePicker, but that also feels wrong. I'm guessing the solution will involve combine and perhaps a publisher, but I don't yet understand how to implement this. Any assistance would be appreciated. Thanks, Mike
1
0
373
Jul ’20
I think I need to use Combine, but I'm not yet sure how...
I have a row view that shows the details of a podcast object. It includes a Subscribe/Unsubscribe button (displayed text depends on whether the user is currently subscribed.) (podcast uses a computed property to express isSubscribed) This means when a user taps the button, the Subscribe/Unsubscribe text should change, but it does not. I'm pretty sure I need to use combine for the podcast model object to publish an event, but I don't yet know what this code looks like. Any chance somebody could let me know how I need to extend the code below to do this? thanks, Mike class SubscriptionsManager {     var subscriptions: [Podcast] = []     static let shared = SubscriptionsManager()     func toggleSubscription(podcast: Podcast) {     }     func isSubscribed(podcast: Podcast) -> Bool {         let result = subscriptions.first{ $0.id == podcast.id }         return result != nil     } } class Podcast: Codable {     let title: String     let id: String     var isSubscribed: Bool {         return SubscriptionsManager.shared.isSubscribed(podcast: self)     }     func toggleSubscription() {         SubscriptionsManager.shared.toggleSubscription(podcast: self)     } } struct PodcastRowView: View {     @State var podcast: Podcast     var buttonText: String {         return podcast.isSubscribed ? "Unsubscribe" : "Subscribe"     }     var body: some View {         HStack {             Text(podcast.title)             Button(action: {                 self.podcast.toggleSubscription()             }) {                 Text(self.buttonText)             }         }     } }
3
0
589
Jul ’20
How can I pass Content into a function that will return a swiftUI Container view?
I'm attempting to create a function that will return a swiftUI container. Something like this:     func myStack(content: Text) -> some View {         ZStack{             if self.shouldBeHorizontal() {                 HStack(alignment: .center, spacing: 10, content: {content})             } else {                 VStack(alignment: .center, spacing: 10, content: {content})             }         }     } However, I really want toe content input to be more generic. When I change the function declaration to     func myStack(content: ZStack) -> some View { The compiler seems to require me to specify the details of the content of the ZStack. Alternatively, when I try this:     func myStack(content: () -> Content) -> some View { It complains that Content is an undeclared type. any/all help greatly appreciated. thanks, Mike
4
0
3k
Jun ’20
how to declare a variable that will later be defined as a SwiftUI view?
I can refactor, to avoid having to do this, but what can I use as the var type in the snippet below:var mySwiftUIView: __________? if shouldUseFancyView() { mySwiftUIView = FancyView(param: paramValue) } else { mySwiftUIView = PlainView(param: otherParamValue) } let hostingView = NSHostingView(rootView: mySwiftUIView)In the API, NSHostingView's rootView appears to be of type Content, but it's not clear to me what Content refers to.thanks in advance,Mike
2
0
1.2k
May ’20
How do I create a dummy or empty Publisher?
I'm having a bit of trouble getting my head around publishers.My current project is targetting macOS and iOS. I found a publisher-based way to handle keyboard height changes that works great in iOS.Now I just need to find a way to create an empty/dummy publisher for macOS.(I can solve this problem other ways, but am feeling embarrassed that I can't figure out how to make this empty publisher.)Any/all guidance appreciated.the code snippet below returns the following error at line 16: Unable to infer closure type in the current contextthanks,extension Publishers { #if os(iOS) static var keyboardHeight: AnyPublisher<cgfloat, never=""> { let willShow = NotificationCenter.default.publisher(for: UIApplication.keyboardWillShowNotification) .map { return $0.keyboardHeight } let willHide = NotificationCenter.default.publisher(for: UIApplication.keyboardWillHideNotification) .map { _ in CGFloat(0) } return MergeMany(willShow, willHide) .eraseToAnyPublisher() } #elseif os(macOS) static var keyboardHeight = AnyPublisher<cgfloat, never=""> { return Empty(completeImmediately: false) } #endif }
2
0
4.1k
May ’20
swiftUI app crashing when running in iOS 13.0 simulator
Behaves fine on devices and simulators with newer versions of iOS(haven't yet found a device still at 13.0 to try it on)There is nothing in the console, just the following error:Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)stackTrace (all Apple code) is shown below.As always, any/all suggestions welcome.thanks.#00x00007fff2c046815 in _LayoutTraits.Dimension.init(min:ideal:max:) ()#10x00007fff2c24a8fd in StackLayout.layoutTraits() ()#20x00007fff2c24a7dc in StackLayout.Storage.layoutTraits() ()#30x00007fff2bfaf2c8 in LayoutTraitsProxy.layoutTraits() ()#40x00007fff2c24cc63 in accumulateSpacing #1 (ofChild:) in StackLayout.Header.init(layoutContext:proxies:majorAxis:minorAxisAlignment:uniformSpacing:childStorage:capacity:) ()#50x00007fff2c24c0a5 in StackLayout.Header.init(layoutContext:proxies:majorAxis:minorAxisAlignment:uniformSpacing:childStorage:capacity:) ()#60x00007fff2c24c9ad in specialized ManagedBufferPointer.init(bufferClass:minimumCapacity:makingHeaderWith:) ()#70x00007fff2c24f11c in specialized closure #2 in HVStack.updateOutput<A>(attributeContext:layoutContext:children:) ()#80x00007fff2c25182a in partial apply for specialized ()#90x00007fff2c369fc7 in specialized static LayoutComputerDelegate.update<A>(_:maybeInPlace:create:) ()#100x00007fff2c377930 in specialized static LayoutComputerDelegate.update<A>(_:maybeInPlace:create:) ()#110x00007fff2c24a34c in specialized HVStack.updateOutput<A>(attributeContext:layoutContext:children:) ()#120x00007fff2c24a3b0 in specialized HVStack.updateOutput<A>(attributeContext:layoutContext:children:) ()#130x00007fff2c26804c in specialized LayoutQuery<>.update(context:) ()#140x00007fff2c0e5b2a in partial apply for protocol witness for static UntypedAttribute._update(_:graph:attribute:) in conformance DynamicLayoutViewChildGeometry ()#150x00007fff2f70e429 in AG::Graph::UpdateStack::update() ()#160x00007fff2f70e6e7 in AG::Graph::update_attribute(unsigned int, bool) ()#170x00007fff2f711ceb in AG::Graph::input_value_ref_slow(unsigned int, unsigned int, AGTypeID, bool*) ()#180x00007fff2bfaf2a9 in LayoutTraitsProxy.layoutTraits() ()#190x00007fff2c24cc63 in accumulateSpacing #1 (ofChild:) in StackLayout.Header.init(layoutContext:proxies:majorAxis:minorAxisAlignment:uniformSpacing:childStorage:capacity:) ()#200x00007fff2c24c0a5 in StackLayout.Header.init(layoutContext:proxies:majorAxis:minorAxisAlignment:uniformSpacing:childStorage:capacity:) ()#210x00007fff2c24c9ad in specialized ManagedBufferPointer.init(bufferClass:minimumCapacity:makingHeaderWith:) ()#220x00007fff2c24f11c in specialized closure #2 in HVStack.updateOutput<A>(attributeContext:layoutContext:children:) ()#230x00007fff2c25182a in partial apply for specialized ()#240x00007fff2c369fc7 in specialized static LayoutComputerDelegate.update<A>(_:maybeInPlace:create:) ()#250x00007fff2c24a34c in specialized HVStack.updateOutput<A>(attributeContext:layoutContext:children:) ()#260x00007fff2c24a220 in specialized HVStack.updateOutput<A>(attributeContext:layoutContext:children:) ()#270x00007fff2c267eac in specialized LayoutQuery<>.update(context:) ()#280x00007fff2c0e5b2a in partial apply for protocol witness for static UntypedAttribute._update(_:graph:attribute:) in conformance DynamicLayoutViewChildGeometry ()#290x00007fff2f70e429 in AG::Graph::UpdateStack::update() ()#300x00007fff2f70e6e7 in AG::Graph::update_attribute(unsigned int, bool) ()#310x00007fff2f711ceb in AG::Graph::input_value_ref_slow(unsigned int, unsigned int, AGTypeID, bool*) ()#320x00007fff2bfaf2a9 in LayoutTraitsProxy.layoutTraits() ()#330x00007fff2c24cc63 in accumulateSpacing #1 (ofChild:) in StackLayout.Header.init(layoutContext:proxies:majorAxis:minorAxisAlignment:uniformSpacing:childStorage:capacity:) ()#340x00007fff2c24c0a5 in StackLayout.Header.init(layoutContext:proxies:majorAxis:minorAxisAlignment:uniformSpacing:childStorage:capacity:) ()#350x00007fff2c24c9ad in specialized ManagedBufferPointer.init(bufferClass:minimumCapacity:makingHeaderWith:) ()#360x00007fff2c24f11c in specialized closure #2 in HVStack.updateOutput<A>(attributeContext:layoutContext:children:) ()#370x00007fff2c25182a in partial apply for specialized ()#380x00007fff2c369fc7 in specialized static LayoutComputerDelegate.update<A>(_:maybeInPlace:create:) ()#390x00007fff2c377930 in specialized static LayoutComputerDelegate.update<A>(_:maybeInPlace:create:) ()#400x00007fff2c24a34c in specialized HVStack.updateOutput<A>(attributeContext:layoutContext:children:) ()#410x00007fff2c24a3b0 in specialized HVStack.updateOutput<A>(attributeContext:layoutContext:children:) ()#420x00007fff2c26804c in specialized LayoutQuery<>.update(context:) ()#430x00007fff2c0e5b2a in partial apply for protocol witness for static UntypedAttribute._update(_:graph:attribute:) in conformance DynamicLayoutViewChildGeometry ()#440x00007fff2f70e429 in AG::Graph::UpdateStack::update() ()#450x00007fff2f70e6e7 in AG::Graph::update_attribute(unsigned int, bool) ()#460x00007fff2f711ceb in AG::Graph::input_value_ref_slow(unsigned int, unsigned int, AGTypeID, bool*) ()#470x00007fff2c4b2f2b in _ZStackLayout.layoutTraits(in:children:) ()#480x00007fff2c26a673 in specialized _LayoutEngine.init(layout:layoutContext:children:) ()#490x00007fff2c4fa650 in specialized _Layout<>.updateOutput<A>(attributeContext:layoutContext:children:) ()#500x00007fff2c4fa594 in specialized _Layout<>.updateOutput<A>(attributeContext:layoutContext:children:) ()#510x00007fff2c2682b4 in specialized LayoutQuery<>.update(context:) ()#520x00007fff2c0e5b2a in partial apply for protocol witness for static UntypedAttribute._update(_:graph:attribute:) in conformance DynamicLayoutViewChildGeometry ()#530x00007fff2f70e429 in AG::Graph::UpdateStack::update() ()#540x00007fff2f70e6e7 in AG::Graph::update_attribute(unsigned int, bool) ()#550x00007fff2f711ceb in AG::Graph::input_value_ref_slow(unsigned int, unsigned int, AGTypeID, bool*) ()#560x00007fff2c4b2f2b in _ZStackLayout.layoutTraits(in:children:) ()#570x00007fff2c26a673 in specialized _LayoutEngine.init(layout:layoutContext:children:) ()#580x00007fff2c4fa650 in specialized _Layout<>.updateOutput<A>(attributeContext:layoutContext:children:) ()#590x00007fff2c4fa594 in specialized _Layout<>.updateOutput<A>(attributeContext:layoutContext:children:) ()#600x00007fff2c2682b4 in specialized LayoutQuery<>.update(context:) ()#610x00007fff2c0e5b2a in partial apply for protocol witness for static UntypedAttribute._update(_:graph:attribute:) in conformance DynamicLayoutViewChildGeometry ()#620x00007fff2f70e429 in AG::Graph::UpdateStack::update() ()#630x00007fff2f70e6e7 in AG::Graph::update_attribute(unsigned int, bool) ()#640x00007fff2f713263 in AG::Subgraph::update(unsigned int) ()#650x00007fff2c0b7110 in ViewGraph.runTransaction(in:) ()#660x00007fff2c0b759d in closure #1 in ViewGraph.updateOutputs(at:) ()#670x00007fff2c0b720b in ViewGraph.updateOutputs(at:) ()#680x00007fff2c40d6ea in closure #1 in closure #1 in ViewRendererHost.render(interval:updateDisplayList:) ()#690x00007fff2c40d46c in closure #1 in ViewRendererHost.render(interval:updateDisplayList:) ()#700x00007fff2c40ad47 in ViewRendererHost.render(interval:updateDisplayList:) ()#710x00007fff2c5a5472 in _UIHostingView.layoutSubviews() ()#720x00007fff2c5a5495 in @objc _UIHostingView.layoutSubviews() ()#730x00007fff47636722 in -[UIView(CALayerDelegate) layoutSublayersOfLayer:] ()#740x00007fff2b030ef9 in -[CALayer layoutSublayers] ()#750x00007fff2b0358ff in CA::Layer::layout_if_needed(CA::Transaction*) ()#760x00007fff2b041fe4 in CA::Layer::layout_and_display_if_needed(CA::Transaction*) ()#770x00007fff2af8a4a8 in CA::Context::commit_transaction(CA::Transaction*, double) ()#780x00007fff2afbfab3 in CA::Transaction::commit() ()#790x00007fff4717a1e1 in __34-[UIApplication _firstCommitBlock]_block_invoke_2 ()#800x00007fff23afb8ec in __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ ()#810x00007fff23afb058 in __CFRunLoopDoBlocks ()#820x00007fff23af5ee4 in __CFRunLoopRun ()#830x00007fff23af56b6 in CFRunLoopRunSpecific ()#840x00007fff3815cbb0 in GSEventRunModal ()#850x00007fff47162a67 in UIApplicationMain ()
3
0
1k
May ’20
Class Protocol in a SwiftUI struct View
I'm attempting to use a UIView subclass in a SwiftUI View-Based designclass MyView: UIView { weak var delegate: MyViewDelegate? ... } protocol MyViewDelegate: class { func somethingHappened() }I was hoping I could just do something like:struct WrapperView: UIViewRepresentable { func makeUIView(context: Context) -> MyView { let result = MyView() result.delegate = self return result } } extension WrapperView: MyViewDelegate { func somethingHappened() { // do delegate stuff } }I find myself in a catch-22WrapperView can not implement MyViewDelegate because it's a class protocol.If I change the protocol to not be class-based, the delegate iVar can no longer be weak.If I remove the weak reference from the delegate var, (I believe) I will be creating a retain cycle any time MyView's delegate ivar is class.I certainly get why weak (and reference counting) are class only, but is there some way I can define the delegate protocol to allow the delegate ivar to be weak, but still possibly refer to struct?my plan B is to change WrapperView to something like:struct WrapperView: UIViewRepresentable { var wrappedViewDelegate: WrappedViewDelegate { return WrappedViewDelegate(parent: self) } func makeUIView(context: Context) -> MyView { let result = MyView() result.delegate = wrappedViewDelegate return result } func somethingHappened() { // do delegate stuff } }class WrappedViewDelegate: MyViewDelegate { weak var parent: WrapperView init(parent: WrapperView) { parent = parent } func somethingHappened() { parent.somethingHappened() } }Does anyone see an alternative to my planB?thanks!
0
0
1.8k
Apr ’20
A question about init of SwiftUI Views
In the 'I don't understand why this is happening' category, I'm attempting to initialize a state variable in a View struct, however the initialized value doesn't appear to be sticking. Can any of you see why?I see the following console output:didSet was calledmodelValue: 0 newValue: 12when I run the code belowalso in the ui the displayed value is 0 when I'd expect it to be 12code:struct ContentView: View { @State var modelValue: Int? { didSet { print("didSet was called") } } init() { updateValue() } func updateValue() { let newValue = 12 modelValue = newValue print("modelValue: \(modelValue ?? 0) newValue: \(newValue)") } var body: some View { Text("displayValue: \(modelValue ?? 0)") } }
2
0
7.3k
Mar ’20
swift syntax getting more complicated with nontrivial swiftUI examples; and Xcode errors are not always helpful, at least to me.
When I start with this, everything compiles fine:struct ContentView1: View { @State var shouldShowRect = false var body: some View { GeometryReader { geometry in ZStack() { VStack() { Text("Hello, World!") Text("Hello, World again?") } if self.shouldShowRect { Rectangle() } } } } }However when I add a let declaration inside GeometryReader, I get a compile error in xcodestruct ContentView2: View { @State var shouldShowRect = false var body: some View { GeometryReader { geometry in let dimension = geometry.size.width ZStack() { VStack() { Text("Hello, World!") Text("Hello, World again?") } if self.shouldShowRect { Rectangle() } } } } }at line 6: Closure containing a declaration cannot be used with function builder 'ViewBuilder'The GeometryReader block now needs to explicitly return a view, so I do this:struct ContentView3: View { @State var shouldShowRect = false var body: some View { GeometryReader { geometry in let dimension = geometry.size.width let result0 = ZStack() { VStack() { Text("Hello, World!") Text("Hello, World again?") } if self.shouldShowRect { Rectangle() } } return result0 } } }This solves the problem at line6, but creates two new problems at lines 4 and 54: Function declares an opaque return type, but has no return statements in its body from which to infer an underlying type5: Cannot convert return expression of type 'GeometryReader<_>' to return type 'some View'I can silence the line4 problem by assigning GeometryReader to a variable and adding a return statement the end of the var body: closure.replace line 05. with the following let result1 = GeometryReader { geometry inadd the following after line 17. return result1but I'm left with two questions:1. how can I silence the error still showing at line5 "cannot convert return expression..."2. Why was the above change (let result1 = GeometryReader...) needed?I have the impression that these two errors, reported at lines 4 & 5 are actually red herrings, and the real syntax problem is somewhere/something else.any/all help greatly appreciated,Mike
1
0
1.6k
Feb ’20
navigating the view hierarchy in SwiftUI
I'm attempting to build an app using SwiftUI, and having getting stuck on a few things that I can't figure out how to implement.The current challenge can be described as follows:1. I am displaying a 9x9 grid2. when a user taps one of the 'cell's I want to present an input view that only requires a portion of the screen. (I'm currently picturing it being non-modal, but feel free to convince me it should be otherwise)3. I want the input view to animate its frame starting from the cell the user taps, and ending being a square in the middle of the screen (either a fixed final size, or a fixed final portion of the smaller screen dimension.. or perhaps an intrinsic size?)Any/all help appreciated.here is some UIViewController-based code that implements what I want to doclass ViewController: UIViewController { override func loadView() { let result = UIView() result.backgroundColor = UIColor.blue addButton(superView: result, title: "button1", yMultiplier: 0.8) addButton(superView: result, title: "button2", yMultiplier: 1.4) view = result } func addButton(superView: UIView, title: String, yMultiplier: CGFloat) { let button = UIButton() button.setTitle(title, for: .normal) button.backgroundColor = UIColor.green button.addTarget(self, action: #selector(buttonTapped(sender:)), for: .touchUpInside) button.translatesAutoresizingMaskIntoConstraints = false superView.addSubview(button) let centerX = NSLayoutConstraint(item: button, attribute: .centerX, relatedBy: .equal, toItem: superView, attribute: .centerX, multiplier: 1.0, constant: 0) let centerY = NSLayoutConstraint(item: button, attribute: .centerY, relatedBy: .equal, toItem: superView, attribute: .centerY, multiplier: yMultiplier, constant: 0) superView.addConstraints([centerX, centerY]) } @objc func buttonTapped(sender: UIButton) { let tempView = UIView(frame: sender.frame) tempView.backgroundColor = UIColor.red tempView.autoresizingMask = [.flexibleWidth, .flexibleHeight] tempView.translatesAutoresizingMaskIntoConstraints = true view.addSubview(tempView) UIView.animate(withDuration: 1.0, animations: { tempView.frame.size = CGSize(width: 200, height: 200) tempView.center = self.view.center }) { (success) in tempView.removeFromSuperview() } }}
0
0
305
Feb ’20
SwiftUI how to create square cells in a grid.. and a couple of other hard to implement requirements
I'm looking to create a grid of square cells. Each square cell will have a 'large' text label in the center and a 'small' textLabel in the bottom left corner.I feel like the pseudo code would look something like:ZStack { Text("3", horizontalAlignment: .center, verticalAlignment: .center) .font(.title) Text("1,2,4", horizontalAlignment: .leading, verticalAlignment: .bottom) .font(.caption) } .border(Color.black, width: 2.0)There would be several rows and several columns of these cells. Their size would then be derived by the number of rows/columns and the available screen space.I've written some code that approximates what I'm going for, but it is using specific frame dimensions.I would prefer to not need specific width/height numbers.struct ContentView: View { var body: some View { ZStack() { Rectangle() .fill(Color.clear) .border(Color.black, width: 2.0) .frame(width: 100, height: 100) Text("4") .font(.title) Text("x") .alignmentGuide(HorizontalAlignment.center) { d in return 45 } .alignmentGuide(VerticalAlignment.center) { d in return -30 } .font(.caption) } } }Grateful for any/all help,Mike
0
1
1.2k
Feb ’20
an (advanced?) animation question
I am currently able to do the following in swiftUI:1. on a button tap, update a model object property2. update a 'separate' swiftUI view (I call it a cell view) that has an @observedObject reference to the model object What I want to do:while updating the cell view, I want to draw attention to it by pulsing its background colour.so the time line would be:1. tap the button2. update the model object2. update the cellView with the model change3. update the cellView background colour (eg Color(white: 0.5))4. animate the cellView background colour back to its original value (eg Color(white: 0.9))Here is code that performs the basic behaviour without the animation.Any/all help with the animation greatly appreciated.thanks,Mikestruct ContentView: View { let model = Model.shared var body: some View { VStack(alignment: .center, spacing: 30.0) { Button(action: { self.model.update() }) { Text("Tap Here") } Cell(model: model) } } } struct Cell: View { @ObservedObject var model: Model var body: some View { Text(model.myVar) .background(Color(white: 0.9)) } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } class Model: ObservableObject { @Published var myVar = "Before" static var shared: Model { return Model() } func update() { myVar = "After" } }
1
0
404
Feb ’20
UIStackView not laying out as expected in a UIScrollView
I'm attempting to put a (vertical) UIStackView in a UIScrollView, but it doesn't seem to want to scroll. Instead it it squishing all the arrangedSubviews into the bounds of the scroll view. autolayout-wise, I'm doing the following:1. constraining the UIScrollView to its superview (top, height, leading and width)2. add a UIView inside the scrollView label it Content View3. constrain the top, bottom, leading, and trailing of the contentView to the scroll view4. constrain contentView's width to match ScrollView's width5. add a vertical UIStackView inside the ContentView6. constrain its top, bottom, leading and trailing values to the contentViewattached is a screen shot link. I have posted a screen shot here: img.gg slash Py9T81yAt the top of the screen shot is a stackview that lays out as expected (not in a scrollView)At the bottom is the stackview inside the scrollView that does not layout correctlyany/all guidance appreciated. (project/source code available if interested)thanks in advance,Mike
10
0
12k
Dec ’19