Hi
I wanted to move some code, that reads from a Core Data table in a SwiftUI View struct, from the body to the init. The NSManagedObjectContext is getting passed around in an environment declaration:
@Environment(\.managedObjectContext) private var viewContext: NSManagedObjectContext
But that doesn't work: the environment variables are not available in the init. There doesn't seem to be a good reason for that. Is there a way to read an environment variable in the init?
I know I could add another parameter to the init, but there are enough already, and that seems like poor style.
Post
Replies
Boosts
Views
Activity
Hi
I really liked the video by Paul Lettieri, creating a replacement for HStack that gives equal width to each, so I wrote one for my app. But the app doesn't compile for me. It gives me "Trailing closure passed to parameter of type 'HorizontalAlignment' that does not accept a closure" against the top VStack, not the place where the equal lengths HStack replacement appears.
This is my version of his struct:
extension LayoutSubviews {
func maxSize() -> CGSize {
let subviewSizes = map { $0.sizeThatFits(.unspecified) }
return subviewSizes.reduce(CGSize.zero) { CGSize(width: Swift.max($0.width, $1.width), height: Swift.max($0.height, $1.height)) }
}// maxSize()
func spacing() -> [Double] {
return indices.map { index in
guard index < count - 1 else { return 0.0 }
return self[index].spacing.distance(to: self[index + 1].spacing, along: .horizontal)
}
}// spacing()
}// extension LayoutSubviews
struct EqualWidthHStack: Layout {
func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
let maxsize = subviews.maxSize()
let totalSpacing = subviews.spacing().reduce(0) { $0 + $1 }
return CGSize(width: maxsize.width * Double(subviews.count) + totalSpacing, height: maxsize.height)
}// sizeThatFits
func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
let maxsize = subviews.maxSize()
let spacing = subviews.spacing()
let sizeProposal = ProposedViewSize(width: maxsize.width, height: maxsize.height)
var x = bounds.minX + maxsize.width / 2
for index in subviews.indices {
subviews[index].place(at: CGPoint(x: x, y: bounds.midX), anchor: .center, proposal: sizeProposal)
x += maxsize.width + spacing[index]
}
}// placeSubviews
}// EqualWidthHStack
I wrote this trivial View to test it:
struct ContentView: View {
var body: some View {
VStack {
HStack {
Button("Hi") { print("Hi!") }
Button("Hello") { print("Hello!") }
Button("Good evening") { print("Good evening!") }
}
EqualWidthHStack {
Button("Hi") { print("Hi!") }
Button("Hello") { print("Hello!") }
Button("Good evening") { print("Good evening!") }
}
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, world!")
}
}
}
I'm using Version 14.0 beta 2 (14A5229c) of Xcode. I was having a problem with the exact same message in another app with a much more complex main view.
I hope someone can tell me what to do or what is going on here.
Regards,
Mark
Can anyone confirm that there is at present no equivalent on the TextField view to the UITextFieldDelegate method
textField(_:shouldChangeCharactersIn:replacementString:)
i.e. one that can intercept each keystroke and and paste to ensure that the value is always valid?
In SwiftUI the onEditingChanged parameter in the constructor is not triggered with each character entered.
My app gets killed with the error message:
Actions added to UIAlertController of style UIAlertActionStyleDefault must have a title when running in UIUserInterfaceIdiomPhone
if I use one sort of button, but not the shorter sort. This code produces the error, but it I remove the button with Image(systemName:) I get that error.
Button(action: { showingExtras = true } ) {
Image(systemName: "ellipsis.rectangle")
}
.confirmationDialog("Extras", isPresented: $showingExtras) {
Button(action: { showingCashSummary = true} ) {
Image(systemName: "banknote")
}
Button("Cash summary") { showingCashSummary = true }
Button("Allocation summary") {showingAllocationSummary = true}
Button("Export") { isExporting = true }
}
Is there some way to add the title that UIAlertController requires?
I was trying out the use of Sequence and IteratorProtocol. But something here surprised me. There is no error on the for statement but the while statement has the error "Cannot use mutating member on immutable value: 'threeToGo' is a 'let' constant".
This looks like an inconsistency in Swift. They are both mutating the threeToGo variable. Can anyone give an explanation?
func even(_ i: Int) -> Bool { i % 2 == 0 }
struct Countdown: Sequence, IteratorProtocol {
var count: Int
mutating func next() -> Int? {
if count == 0 {
return nil
} else {
defer { count -= 1 }
return count
}
}
}
let threeToGo = Countdown(count: 3)
while let i = threeToGo.next() {
print(i)
if even(i) { break }
}
print("We broke out")
for i in threeToGo {
print(i)
}
HiI wanted to change the name of a variable in XCode 9 9M136h. So, I selected the name, brought up the context menu and clicked on Rename. I got an error dialog saying:Rename failedRefactoring engine reported no changes for the initial file.Is this a bug in xcode?RegardsMark
I hope there is a solution to this. I am writing a money counting app. Here is a code snippet from the View body where the keyboard toolbar is created. Each cashCountRow has a denomination of cash, like $10, a TextEdit to enter the number counted, and a total. I have placed 3 buttons, one to dismiss the keyboard, one to advance focus to the next row, and one to move focus to the preceding row. That all works fine.
The problem is that after leaving the screen with this on it, those buttons remain on the keyboard, even when I want nothing. They are greyed out, somehow. If I visit a page before this keyboard toolbar is set up, the keyboard is clear of toolbar buttons as I want, but once I have brought up the keyboard for the cash count rows, those buttons hang around.
Group {
ForEach(CoinNote.allCases.reversed(), id: \.self) { cn in
ForEach(data.cashCountRows.filter( { $0.nc.coinNote == cn } )) { cashCountRow in
cashCountRow
.focused($focusIndex, equals: cashCountRow.index)
.frame(height: data.calcNcSize.height)
}
TotalRow(data: data, title: cn.name, total: totals[cn])
.padding(.bottom)
}// ForEach
}// Group
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
Button("Done") {
focusIndex = nil
}
Spacer()
Button("Prev") {
focusIndex = ((focusIndex ?? 0) - 1).mod(data.cashCountRows.count)
}
Button("Next") {
focusIndex = ((focusIndex ?? 0) + 1).mod(data.cashCountRows.count)
}
}
}// toolbar
I want to allow the OK button to return from a scene to the calling form. But when I add
@Environment(\.dismiss) private var dismiss: DismissAction
which I use in a number of other views, a spurious error appears.
This seems to be a bug in the IDE, though I hate to say that.
Here is photographic evidence:
No error here:
Error here:
Can anyone shed any light on this?
I have a master detail arrangement of 2 views, a list on one from which the user selects a record in Core Data which links to a detail view (NavigationLink) where the user edits the corresponding record. On the edit view there is a Save button, but the big default dismiss button provided to the NavigationLink lets the user dismiss the view without saving, which is likely to happen.
Is there some modifier / event handler that will let me throw up an alert if the user has unsaved edits?
Hi
I am writing a view that the user to select a value from a list as they fill in a calling view, and at the trailing edge of each row in the list is a button that allows the user to change the value in the list:
I started with this code
List {
ForEach(getResults(), id: \.objectID) { item in
HStack {
Text(itemValue(item: item))
.onTapGesture {
onAccept(item)
dismiss()
}
Spacer()
Button(action: { currentItem = item }) {
Image(systemName: "square.and.pencil")
}
}
}
}
The trouble with it is that the button to the right which brings up the view for renaming is expected to be used rarely, and the main purpose of this list is to select a value from the list. However, the tappable area of the Button includes the whole free space row, while the tappable area of the Text is just the extent of the visible text, the reverse of what I want.
I got the desired behaviour by switching view types and forcing the font colours to be what they were in the first code:
HStack {
Button(itemValue(item: item)) {
onAccept(item)
dismiss()
}
.foregroundColor(.primary)
Spacer()
Image(systemName: "square.and.pencil")
.foregroundColor(.accentColor)
.onTapGesture {
currentItem = item
}
}
Is there a way to get the desired tappable areas with the view types I wanted at first and thus to avoid overriding the foreground colour ?
I have a list that allows deleting and moving. And there is an EditButton associated with the List :
List {
ForEach(conversions) { Text($0.line) }
.onDelete(perform: deleteConversion)
.onMove(perform: moveConversion)
}
When I swipe left one of the rows of the List, a red rectangular Delete button appears at the right edge of the row. Clicking it does nothing. If I click on the EditButton, each row gets a round "-" button on the left, and again clicking it does nothing.
It's not all bad. If the left swipe on a row is taken far enough, deleteConversion gets called. And when the EditButton is pressed, the little 3-line grab handle appears at the right of each row allows the user to reorder the list.
I am trying to convert an existing UIKit project into a SwiftUI project in Xcode 13. Because of all the autogenerated class files and the helpful defaults that Xcode provides, just dragging in the xcdatamodel file didn't do it.
Is there an approved way to do this?
Hi
I recently got my first app up for sale in the iOS App Store, and accidentally clicked on the macOS App link.
I would like to reset that back to nothing for macOS app, but there doesn't seem to be a way to do it. Some people on stack overflow suggest that if you hover the mouse cursor over the unwanted entry it will show a delete button:
https://stackoverflow.com/questions/63507911/how-to-remove-automatically-created-macos-app-from-app-store-connect
but that doesn't happen for me.
HiI have a 256 GB machine which is running out of room. It turns out that ~/Library/Developer/XCode/iOS DeviceSupport consumes 121 GB of that (according to CleanMyMac X).That folder is divided into a number of subfolders which must serve each version of iOS: E.g. you have 13.0 (17A577), 13.1 (17A844), 13.1.2 (17A844), etc. It starts at 7.1.2 and goes up to 13.2.3. There are 56 in all, and they occupy about 3 GB each.Should I just delete all the ones I am not going to use to free up space? Or is there some setting in XCode that controls that?TIAMark
Hi
I have a simple UIKit app that lets the user enter temperatures in floating point and converts them to a different unit. So steer the user in the right direction, first I made the UITextField.keyboardType property = decimalPad.
Then I set the UITextField.delegate to a UITextFieldDelegate with the method textfield(:shouldChangeCharactersIn:replacementString)
I want to convert the app to SwiftUI but I haven't found any equivalents for those .
Are there replacements for those?