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
Post
Replies
Boosts
Views
Activity
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)
}
}
}
}
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
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
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
}
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 ()
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!
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)")
}
}
I'm getting this error when attempting to upload an iOS app to iTunes Connect. I've tried using Transporter, and get the same result.I've also tried uploading a new version of an app that uploaded correctly in November and got the same result.Does anyone have any suggestions for possible causes for this error?thanks,
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
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()
}
}}
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
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"
}
}
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