Hi,
I'm trying to test a view model that conforms to ObservableObject with swift testing.
My test looks like
@Test("When a filter is selected the 'save search' button is enabled")
func testWhenAFilterIsSelectedTheSaveButtonIsEnabled() {
let viewModel = GxClassSearchFormViewModel(
filterSelection: .init(),
currentSavedSearch: nil
)
// when
viewModel.filterSelection.clubs.select(hasle)
// then
#expect(viewModel.savedSearchState == .active)
#expect(viewModel.isSavedSearchButtonDisabled)
}
Interestingly, this test crashes on the iOS 16.2 Simulator. I'm using Version 16.2 (16C5032a)
It crashes at the macro level like:
And I don't understand what's wrong really. Maybe a concurrency issue? not sure.
Xcode stops the execution and the debug navigator shows and incredibly long stack trace. I add images from the top and bottom of it as it's too long to add it all
Has anyone experience a similar issue?
It has happened to me in other tests too, sometimes when using #required
Post
Replies
Boosts
Views
Activity
Hi,
I'm a bit stuck when it comes to implementing live activities.
I'm trying to start one by sending a push.
my activity attributes looks like:
import Foundation
import ActivityKit
public struct NeoPrototypeActivity: ActivityAttributes {
public let classId: String
public let name: String
public let room: String
public let startTime: Date
public init(classId: String, name: String, room: String, startTime: Date) {
self.classId = classId
self.name = name
self.room = room
self.startTime = startTime
}
public struct ContentState: Codable & Hashable {
public let participationState: ParticipationState
public init(participationState: ParticipationState) {
self.participationState = participationState
}
}
}
public enum ParticipationState: String, Codable, Hashable, Equatable {
case upcoming
case upcomingOnWaitingList
case checkedIn
case waitingList
case lostSpot
case lostSpotFromWaitingList
case classCompleted
public var description: String {
switch self {
case .upcoming: return "Upcoming"
case .upcomingOnWaitingList: return "Upcoming on Waiting List"
case .checkedIn: return "Checked In"
case .waitingList: return "Waiting List"
case .lostSpot: return "Lost Spot"
case .lostSpotFromWaitingList: return "Lost Spot from Waiting List"
case .classCompleted: return "Class completed"
}
}
}
which I have in a SPM package that is imported by my widget and iOS targets.
Then I am sending a push notification (to my simulator in this case) with the following payload
{
"aps": {
"timestamp": 1728419211,
"event": "start",
"content-state": {
"participationState": "upcoming"
},
"attributes-type": "NeoPrototypeActivity",
"attributes": {
"classId": "1234",
"name": "Indoor Running",
"room": "room 2",
"startTime": "2024-10-19T13:22:59+02:00"
},
"alert": {
"title": "Hola Mundo",
"body": "Todo Bien"
}
}
}
I am using the right values for the deviceID when sending the push.
I get a 200 ok from the CloudKit console.
yet my live activity doesn't start.
I'm trying to look at the errors in the Console app and the only relevant thing is see is:
[NeoPrototypeActivity] Error creating activity: NSCocoaErrorDomain (4864) The data couldn’t be read because it isn’t in the correct format.
It seems like a decoding error, but I don't know what exactly failed
I wrote some test to try the decoding like:
import Testing
import Foundation
@testable import PrototypeActivities
@Test func decoding() async throws {
struct StateContainer: Codable {
let participationState: ParticipationState
}
let jsonString = """
{
"participationState": "upcoming"
}
"""
let json = try #require(jsonString.data(using: .utf8))
let result = try JSONDecoder().decode(StateContainer.self, from: json)
#expect(result.participationState == .upcoming)
}
@Test func decodingActivity() throws {
// let jsonString = """
// {
// "classId": "1234",
// "name": "Indoor Running",
// "room": "room 2",
// "startTime": "2024-10-19T11:22:59Z"
// }
// """
let jsonString = """
{
"classId": "1234",
"name": "Indoor Running",
"room": "room 2",
"startTime": 1729337784
}
"""
let json = try #require(jsonString.data(using: .utf8))
let jsonDecoder = JSONDecoder()
// jsonDecoder.dateDecodingStrategy = .iso8601
let activity = try jsonDecoder.decode(NeoPrototypeActivity.self, from: json)
#expect(activity.classId == "1234")
#expect(activity.name == "Indoor Running")
}```
but even with using the default JSON decoder date format, I still get the same error.
Not sure how to fix this or to get more details.
Hi,
I’m using the snapshot testing library from https://github.com/pointfreeco/swift-snapshot-testing
I recorded the snapshot tests on the iPhone 15 pro simulator on iOS 17.4 and Xcode 15.3 On my M1 Max MacBook Pro
Within the tests found in https://github.com/fespinoza/sample-json-app/blob/84b81ee3fa1d24e97bbeded65487b32258a42325/SampleProjectTests/MovieDetails/MovieDetailsViewTests.swift
I try to control all the traits and properties I can, to make sure the test is run in the same environment in Xcode Cloud
For some reason though, on Xcode Cloud, Text with multiline strings have a different line height than on my machine and thus the test fail
I don’t understand:
why that happens
how to debug this situation
Does anyone here have any pointers?
Reference Image
From my machine
Failure Image
from Xcode Cloud
P.S. thread initially posted in https://github.com/pointfreeco/swift-snapshot-testing/discussions/842 but i haven’t gotten any answers, trying here instead
I'm using Xcode 15 15A240d
Similarly to https://developer.apple.com/forums/thread/731732 when I try to run the Xcode previews for watchOS views in a watchOS target I get compilation errors from UIKit code.
This is only valid for Xcode Previews. Building the code normally / Run it on simulator or device works.
I don't understand why Xcode attempts to build iOS code.
my scheme does include the host app for the watch
I made a duplicate of that scheme by unchecking the host app and that makes previews work again.
I'm not sure this is the intended behavior. I double checked and this was not the case with Xcode 14.3.1 I could run the initial target without issues on Xcode previews.
Do you experience the same issue? is this a problem with my scheme settings or an Xcode bug?
I work in an app that has a companion Apple Watch app.
Previously, we used a token for authenticate request that didn't really expire, now we are fixing this and using an OAuth provider for the authentication token.
Now, with the username/password of the user we get an OAuth token for the iOS app. We can refresh the OAuth token only once, after that, the refresh token gets invalidated. That's not a problem for the iOS app as we get a new access/refresh token.
In the case of the watch app. I'm curious which kinds of strategies do people use to authenticate the user in the watch app.
Previously, we just shared the non-expiring token via watch connectivity and that was good enough. Now we won't be able to do that with the iOS app's OAuth token, as we can only use the refresh token once. So sharing that token between 2 apps doesn't work.
I wonder what people use in this situation? specially for users that are already logged in, so we cannot get an independent token for the watch app with the username/password combination.
how do you use OAuth between the iOS and watchOS apps?
which oauth flows do you use in your apps?
how would you solve this case?
thanks!
I have the following app hierarchy
SceneDelegate
UIHostingController
RootView: View
UIViewControllerRepresentable
MainViewController: UITabBarController
- first tab
UINavigationController
UIHostingController<SampleContentTabView> 🟡
- second tab
UINavigationController
SampleContentAdapterController: UIViewController
UIHostingController<SampleContentTabView> 🔴
With a sample view like
struct SampleContentTabView: View {
@State var name: String = "sample"
var body: some View {
Text(name)
.navigationTitle("\(name) view")
}
}
The thing is that the first tab will correctly set the navigation title in the case of 🟡, but not in the second tab with 🔴
Is this an issue with SwiftUI?
Am I missing something?
A simplified version of the SampleContentAdapterController would be like:
class SampleContentAdapterController: UIViewController {
let name: String
init(name: String, color: Color) {
self.name = name
super.init(nibName: nil, bundle: nil)
}
private lazy var hostingController: UIHostingController = {
UIHostingController(
rootView: SampleContentTabView(name: name)
)
}()
var hostingView: UIView { hostingController.view }
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(hostingView)
hostingView.translatesAutoresizingMaskIntoConstraints = false
hostingView.pinToSuperview()
addChild(hostingController)
hostingController.didMove(toParent: self)
}
}
A full runnable version can be found in: https://github.com/fespinoza/reproducing-bugs/tree/main/NavigationBar
Xcode version: 14.1 beta 3 (14B5033e)
It happens often to me that when I try to run the Xcode previews I see a failure of the type
symbol(s) not found for architecture arm64
The full message looks like:
LinkDylibError: Failed to build BannerImageDemoView.swift
Check the issue navigator for any compilation errors.
ld: warning: directory not found for option '-F/Applications/Xcode-beta.app/Contents/SharedFrameworks-iphonesimulator'
Undefined symbols for architecture arm64:
"_$s8SATSCore11BannerImageV13imageViewData5titleAcA0ceF0OSg_SStcfC", referenced from:
_$s7DemoApp011BannerImageA4ViewV0ab20_PreviewReplacement_cdaE2_1E15__preview__body33_E76125F4FD74D49C73B828FC57CA03FALLQrvg7SwiftUI05TupleE0VyAG6SpacerV_8SATSCore0cD0VAKtGyXEfU_ in BannerImageDemoView.1.preview-thunk.o
"_$s8SATSCore11BannerImageV7SwiftUI4ViewAAMc", referenced from:
_$s8SATSCore11BannerImageVAC7SwiftUI4ViewAAWl in BannerImageDemoView.1.preview-thunk.o
"_$s8SATSCore11BannerImageVMa", referenced from:
_$s7DemoApp011BannerImageA4ViewV0ab20_PreviewReplacement_cdaE2_1E15__preview__body33_E76125F4FD74D49C73B828FC57CA03FALLQrvg7SwiftUI05TupleE0VyAG6SpacerV_8SATSCore0cD0VAKtGyXEfU_ in BannerImageDemoView.1.preview-thunk.o
_$s7SwiftUI6VStackVyAA9TupleViewVyAA6SpacerV_8SATSCore11BannerImageVAGtGGWOh in BannerImageDemoView.1.preview-thunk.o
_$s8SATSCore11BannerImageVWOc in BannerImageDemoView.1.preview-thunk.o
_$s8SATSCore11BannerImageVAC7SwiftUI4ViewAAWl in BannerImageDemoView.1.preview-thunk.o
_$s8SATSCore11BannerImageVWOh in BannerImageDemoView.1.preview-thunk.o
_$s7SwiftUI9TupleViewVyAA6SpacerV_8SATSCore11BannerImageVAEtGWOb in BannerImageDemoView.1.preview-thunk.o
_$s7SwiftUI9TupleViewVyAA6SpacerV_8SATSCore11BannerImageVAEtGWOc in BannerImageDemoView.1.preview-thunk.o
...
"_$s8SATSCore11BannerImageVMn", referenced from:
_symbolic _____y_____y___________ACtGG 7SwiftUI6VStackV AA9TupleViewV AA6SpacerV 8SATSCore11BannerImageV in BannerImageDemoView.1.preview-thunk.o
_symbolic _____y_____y_____y___________ACtGG_Qo_ 7SwiftUI4ViewPAAE15navigationTitleyQrAA18LocalizedStringKeyVFQO AA6VStackV AA05TupleC0V AA6SpacerV 8SATSCore11BannerImageV in BannerImageDemoView.1.preview-thunk.o
_symbolic _____y___________ABtG 7SwiftUI9TupleViewV AA6SpacerV 8SATSCore11BannerImageV in BannerImageDemoView.1.preview-thunk.o
_symbolic _____y___________y___________ADtGG 7SwiftUI13_VariadicViewO4TreeV AA13_VStackLayoutV AA05TupleD0V AA6SpacerV 8SATSCore11BannerImageV in BannerImageDemoView.1.preview-thunk.o
_symbolic ___________AAt 7SwiftUI6SpacerV 8SATSCore11BannerImageV in BannerImageDemoView.1.preview-thunk.o
"_$s8SATSCore13ImageViewDataOMa", referenced from:
_$s7DemoApp011BannerImageA4ViewV0ab20_PreviewReplacement_cdaE2_1E15__preview__body33_E76125F4FD74D49C73B828FC57CA03FALLQrvg7SwiftUI05TupleE0VyAG6SpacerV_8SATSCore0cD0VAKtGyXEfU_ in BannerImageDemoView.1.preview-thunk.o
_$s7SwiftUI6VStackVyAA9TupleViewVyAA6SpacerV_8SATSCore11BannerImageVAGtGGWOh in BannerImageDemoView.1.preview-thunk.o
_$s8SATSCore11BannerImageVWOc in BannerImageDemoView.1.preview-thunk.o
_$s8SATSCore11BannerImageVWOh in BannerImageDemoView.1.preview-thunk.o
_$s7SwiftUI9TupleViewVyAA6SpacerV_8SATSCore11BannerImageVAEtGWOb in BannerImageDemoView.1.preview-thunk.o
_$s7SwiftUI9TupleViewVyAA6SpacerV_8SATSCore11BannerImageVAEtGWOc in BannerImageDemoView.1.preview-thunk.o
_$s7SwiftUI9TupleViewVyAA6SpacerV_8SATSCore11BannerImageVAEtGWOh in BannerImageDemoView.1.preview-thunk.o
...
"_$s8SATSCore13ImageViewDataOMn", referenced from:
_symbolic _____Sg 8SATSCore13ImageViewDataO in BannerImageDemoView.1.preview-thunk.o
ld: symbol(s) not found for architecture arm64
This happens when trying to build the previews for this file
https://github.com/sats-group/SATSCore-iOS/blob/main/DemoApp/DemoApp/Views/Components/BannerImage/BannerImageDemoView.swift
our set up is:
The DemoApp is inside the repo of the library called SATSCore
SATSCore references a private SPM package dependency called SATSType that contains the private font assets
I am not that familiar on how linkers work and why it's failing on Xcode previews.
This happens to me in several version of Xcode 14.
In Xcode 13.4.1 this doesn't happen.
I would like to understand this error, as it's any way to solve this (tried the typical remove derived data + restarting Xcode), so any insights to understand more this kinds of errors would be very helpful.
Thanks
For some time, whenever I use ⌘⇧A (command + shift + A) to toggle appearance from light to dark mode, nothing happens.
The same hen pressing the Features > Toggle Appearance in the menu item.
I saw a mention about this issue in https://developer.apple.com/forums/thread/707994?answerId=716995022#716995022
For that, I assume it may not be a systematic issue, but a problem with some cached file or something in the simulator and/or Xcode project
I've been building our app to make a release in App Store with Xcode Cloud
Currently the builds are failing with the following error:
The value of CFBundleShortVersionString in your WatchKit app's Info.plist (3.9.0) does not match the value in your companion app's Info.plist (4.7.0). These values are required to match.
This is strange, as in our ci_pre_xcodebuild script we have an invocation of the code
echo "Version: ${versionNumber}"
echo "Setting version string in plists"
echo "iOS Version:"
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $versionNumber" $CI_WORKSPACE/MainApp/Resources/Plists/Info.plist
/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString $versionNumber" $CI_WORKSPACE/MainApp/Resources/Plists/Info.plist
echo "Watch Version:"
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $versionNumber" $CI_WORKSPACE/WatchApp/Info.plist
/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString $versionNumber" $CI_WORKSPACE/WatchApp/Info.plist
echo "Watch Extension Version:"
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $versionNumber" $CI_WORKSPACE/WatchAppExtension/Resources/Info.plist
/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString $versionNumber" $CI_WORKSPACE/WatchAppExtension/Resources/Info.plist
On which the command executes correctly and shows the right output.
Then I don't understand what's going on.
This workflow was working a couple weeks ago and we haven't done a change to it since then.
Any ideas of what could it be?
There was another post - https://developer.apple.com/forums/thread/651748 asking how to use @FocusedBinding .
I'm trying to use @FocusedBinding in the following context.
I have a view that contains a @State array property of type [DeckViewModel]
Within the view, I display the list of those models
I can tap on one item to select it, storing that selection in a @State var currentDeck: DeckViewModel? property.
Then I define the properties needed to use @FocusedBinding
struct FocusedDeckKey : FocusedValueKey {
typealias Value = Binding<DeckViewModel?>
}
extension FocusedValues {
var currentDeck: FocusedDeckKey.Value? {
get { self[FocusedDeckKey.self] }
set { self[FocusedDeckKey.self] = newValue }
}
}
And set the value in the view
.focusedValue(\.currentDeck, $appState.currentDeck)
Finally, in the struct I try to set the preferences I use it like:
struct AppCommands: Commands {
@FocusedBinding(\.currentDeck) private var currentDeck: DeckViewModel?
}
Then I get the following error:
❌ Type of expression is ambiguous without more context Which makes sense, as the FocusedValues.currentDeck is of type Binding<DeckViewModel?>?
So the syntax of
@FocusedBinding(\.currentDeck) private var currentDeck: DeckViewModel?
is not correct for these types. But I am not sure how to express this correctly.
The idea of the binding to an optional value seems ok to me, but it brings this complexity regarding the types and this API.
Then.
How can I make @FocusedBinding work with this optional?
or How should I solve this issue? considering I'm trying to represent the selection of an item of a list
Thanks
I have the following scenario that I want to implement
import SwiftUI
struct Deck: Identifiable {
var id: String { name }
var name: String
}
struct DemoListView: View {
@State var decks: [Deck] = [
Deck(name: "Dark Magician"),
Deck(name: "Eldlich"),
Deck(name: "Hero"),
Deck(name: "Hero Isolde"),
Deck(name: "Orcust"),
Deck(name: "Dino"),
Deck(name: "Salamangreat"),
Deck(name: "Sky Striker"),
]
var body: some View {
NavigationView {
List {
ForEach(0..<decks.count) { index in
DemoItemView(text: decks[index].name)
}
}
.listStyle(SidebarListStyle())
.frame(minWidth: 200, alignment: .leading)
}
}
}
struct DemoItemView: View {
@Binding var text: String
@State var isEditing: Bool = false
var body: some View {
Group {
if isEditing {
TextField(text, text: $text, onCommit: { isEditing.toggle() })
.textFieldStyle(PlainTextFieldStyle())
} else {
HStack {
Text(text)
.font(.headline)
Spacer()
}
}
}
}
}
In summary:
I have a list of Deck models
I want to display them on a List
If an element of the list is double tapped then I will toggle the element's isEditing property
when the text is editing, I will use a TextField that needs a binding to the edited text
the text comes from a property of Deck, which is an element in the array
The line of code
DemoItemView(text: decks[index].name)
Is not correct, but this is why I am trying to achieve. I'm trying to get a binding to an element of the collection if that's even possible.
Maybe I took the wrong approach to solve this problem, if so I would like some advice.
At the end I want to implement a list of element and be able to edit inline the text of those elements (in macOS).