Posts

Post not yet marked as solved
0 Replies
505 Views
TLDR: How can I listen to changes in SwiftData and share the data via WatchConnectivity? I am developing an app for the Apple Watch where the iPhone can act as a remote for the Watch. The App on the Watch should work independently from iPhone. The user can create elements on the Watch and start the action associated with the element. The iPhone user can see the elements created on the Watch and start the action on the Watch from the iPhone (if possible I want to add the functionality to let the user update the elements on both devices, but that's not a priority atm). I tried to get it to work with CloudKit and SwiftData, but somehow I couldn't get CloudKit to initialize correctly. After further research, I reconned that using WatchConnectivity and ApplicationContext should be a suitable approach. To communicate with the iPhone App, I created a singleton class that manages the communication. Now I want this class to listen to the changes in SwiftData to send the elements to the iPhone, but I don't know how I can get access to the ModelContext in the Communicator class. I read that passing the value from the initializer of a view is not good practice and it didn't work for me. What would be a suitable way to achieve the desired behavior of my app? Any help and feedback is appreciated. TIA
Posted
by De Mo.
Last updated
.
Post not yet marked as solved
2 Replies
804 Views
I want to add shortcut and Siri support using the new AppIntents framework. Running my intent using shortcuts or from spotlight works fine, as the touch based UI for the disambiguation is shown. However, when I ask Siri to perform this action, she gets into a loop of asking me the question to set the parameter. My AppIntent is implemented as following: struct StartSessionIntent: AppIntent { static var title: LocalizedStringResource = "start_recording" @Parameter(title: "activity", requestValueDialog: IntentDialog("which_activity")) var activity: ActivityEntity @MainActor func perform() async throws -> some IntentResult & ProvidesDialog { let activityToSelect: ActivityEntity = self.activity guard let selectedActivity = Activity[activityToSelect.name] else { return .result(dialog: "activity_not_found") } ... return .result(dialog: "recording_started \(selectedActivity.name.localized())") } } The ActivityEntity is implemented like this: struct ActivityEntity: AppEntity { static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "activity") typealias DefaultQuery = MobilityActivityQuery static var defaultQuery: MobilityActivityQuery = MobilityActivityQuery() var id: String var name: String var icon: String var displayRepresentation: DisplayRepresentation { DisplayRepresentation(title: "\(self.name.localized())", image: .init(systemName: self.icon)) } } struct MobilityActivityQuery: EntityQuery { func entities(for identifiers: [String]) async throws -> [ActivityEntity] { Activity.all()?.compactMap({ activity in identifiers.contains(where: { $0 == activity.name }) ? ActivityEntity(id: activity.name, name: activity.name, icon: activity.icon) : nil }) ?? [] } func suggestedEntities() async throws -> [ActivityEntity] { Activity.all()?.compactMap({ activity in ActivityEntity(id: activity.name, name: activity.name, icon: activity.icon) }) ?? [] } } Has anyone an idea what might be causing this and how I can fix this behavior? Thanks in advance
Posted
by De Mo.
Last updated
.
Post marked as solved
1 Replies
446 Views
I am trying to include AppIntents into my app. To achieve this, I am following Apple‘s WWDC Session. Everything works great until I try to add a parameter to my intent. My Entity and Query look like this: struct ActivityEntity: AppEntity { var id: String var name: String static var typeDisplayRepresentation: TypeDisplayRepresentation = .init(name: "Activity") var displayRepresentation: DisplayRepresentation { DisplayRepresentation(title: LocalizedStringResource(stringLiteral: self.name)) } static var defaultQuery: MobilityActivityQuery = MobilityActivityQuery() } struct MobilityActivityQuery: EntityQuery { func entities(for identifiers: [String]) async throws -> [ActivityEntity] { Activity.all()?.compactMap({ activity in identifiers.contains(where: { $0 == activity.name }) ? ActivityEntity(id: activity.name, name: activity.name) : nil }) ?? [] } } My Intent looks like this: struct StartSessionIntent: AppIntent { static var title: LocalizedStringResource = "Start Recording" @Parameter(title: "Activity") var activity: ActivityEntity? func perform() async throws -> some IntentResult & ProvidesDialog { var activityToSelect: ActivityEntity? = self.activity if activityToSelect == nil { activityToSelect = try await self.$activity.requestDisambiguation(among: Activity.all()?.map { ActivityEntity(id: $0.name, name: $0.name) } ?? []) } guard let selectedActivity = Activity[activityToSelect?.name ?? ""] else { return .result(dialog: "Failed to get activity") } Session.shared.setActivity(activity: selectedActivity) Session.shared.startSession() return .result(dialog: "Okay, starting to record this mobility") } } As soon as the perform method accesses activity, the execution fails and I get the notification from Shortcuts saying: The action contains invalid metadata. In the console the only message I get is this: [Execution] Unknown NSError Communication with the Helping-App is not possible. (this might be a bad translation from me) I am completely clueless on how I can debug this problem and my internet search didn‘t help either. Any help is much appreciated. Thanks in advance
Posted
by De Mo.
Last updated
.
Post marked as solved
8 Replies
16k Views
I want to insert a new outlet for a stack view, but every time I click connedt, this error appears: "Could not insert new outlet connection: Could not find a classs named ViewController in the language Swift". I tried to clear the project and reopened it, but nothing changed. In my other projects it works just fine. I think the only thing I did was updating Xcode in the AppStore. Is it a problem with Xcode or can I do anything to fix this error?
Posted
by De Mo.
Last updated
.
Post not yet marked as solved
2 Replies
595 Views
I want to send multiple messages to a web socket like this: let session = URLSession(configuration: .default) var socket = session.webSocketTask(with: URLRequest(url: self.url, timeoutInterval: 30) socket.resume() do { for message in messages { try await socket.send(message) } } catch { print(error) } Sometimes all messages are sent, but most times the 10th messages simply does not finish nor fail. I even added delegate methods to detect if the socket is closed or if something failed, but those delegate methods never get called. The send simply does not return nor throw. I thought that adding the timeoutInterval would cause the send to fail if it didn’t succeed after 30 seconds, but that does not seem to be the case. Has anyone an idea what could be happening here and how I can resolve this? Any help is greatly appreciated, thanks in advance. PS: the message it failed on mostly is only about 79 Bytes, so it should not take that long to send, especially since sending far longer messages works just fine EDIT: I just tried to use the synchronous version of send with the completionHandler as I hoped that maybe the async version might be bugged, but I have the same problem using that, no completion handler is called
Posted
by De Mo.
Last updated
.
Post not yet marked as solved
0 Replies
808 Views
I am currently working on monitoring the motions of a person using headphones a the  CMHeadphoneMotionManager. Since I want to process the motion, I need the updates to be as frequently as possible to improve the quality of the data. In addition to processing the data, I want to display it live in a chart and save the data to  CoreData  in order to access them later and try other methods for processing on previously recorded data. I created a UML diagram of my current approach: The  MotionManagerProtocol  is the protocol of the class MotionManager, which handles the CMHeadphoneMotionManager. MotionManager.start looks like this: func start() { self.manager.startDeviceMotionUpdates(to: OperationQueue.main) { motion, error in if let motion { let timestamp = CACurrentMediaTime() self.timeInterval = self.oldTimestamp < 0 ? 0 : timestamp - self.oldTimestamp self.oldTimestamp = timestamp self.userAcceleration = motion.userAcceleration self.rotationRate = motion.rotationRate self.attitude = motion.attitude } if let error { print(error) } } } The attributes like  userAcceleration  etc are just setting the value of the  CurrentValueSubject  so that other classes can subscribe to changes in them. The MotionRecorder, MotionViewModel and SpeedCalculator are simply subscribing to changes in the CurrentValueSubject of the MotionManager to be notified when new data is available. In order to be sure, that all are using the same MotionManager, I created a Singleton for it. Is this structure of my code a decent approach or are there anything I can change to make it scale better and receive the new motion data as fast as possible? Since I am pretty early in the process, I can don’t really loose anything if I have to change the whole architecture of my code, so feel free to give advice in this direction as well. Any advice and tips on what to learn in order to improve this project are very much appreciated and TIA. PS: I am using SwiftUI as my framework of choice
Posted
by De Mo.
Last updated
.
Post not yet marked as solved
0 Replies
683 Views
I want to move entries in a List between Sections. The .onMove()  modifier does not work between sections, so I figured I could use normal drag and drop. I found a good example on how to do this between two Lists, but since I don’t want to drag between two Lists, but between the Sections, the Example does not work. I tried to modify the example to not have two separate Lists in a Stack. Now when I try to insert my element into another section, .onInsert() is always called on the section where I dragged it from, no matter where I drop it. Is this simply a limitation of SwiftUI or am I missing something? Any advice on better solutions for this is also very much appreciated. Thanks in advance
Posted
by De Mo.
Last updated
.
Post not yet marked as solved
0 Replies
720 Views
I am calling Swifter.authorize(withCallback: URL, presentingFrom: UIViewController, success: Swifter.TokenSuccessHandler, failure: Swifter.TokenFailureHandler) from a buttonpress in a UIViewControllerRepresentable . When clicking the Button, I am directed to a website in Safari to authorize my App. So far so good. After authorizing my app and getting returned by the Callback URL: “MyTwitterApp://“ neither the code inside Swifter.TokenSuccessHandler nor inside Swifter.TokenFailureHandler is run. Even the debugger does not step into it. In addition, at buildtime I get many warnings about init(account:) being deprecated since iOS 11.0 along other stuff. As I am using the newest version of Swifter and as I have found a fairly recent tutorial (definitely created after the launch of iOS 11) showing Swifter working, I am not sure if that creates any problem. However, my main complaint is, that I am not able to authorize my app, as the code in success is not accessed.
Posted
by De Mo.
Last updated
.
Post not yet marked as solved
3 Replies
5.7k Views
I want my app to decide whether sleep mode should be enabled by checking how many bluetooth peripherals are connected. For bluetooth I created a Singleton, which contains an array of all the connected peripherals. To disable sleep mode I found the following line of code online:UIApplication.shared.isIdleTimerDisabled = trueSince the state of the sleep mode should always be updated after the number of connected peripherals changed, I could not figure out where to put that line of code.Sorry if that's a novice question, but I am pretty new to programming, so I would appreciate any help. Maybe there is a better way to achieve the wanted behavior and I would be happy to learn about it. Thanks in advance.
Posted
by De Mo.
Last updated
.
Post not yet marked as solved
2 Replies
3.8k Views
I am trying to create a progress bar which updates based on two values received via bluetooth (should represent a race like thing, so based on which value is higher, the progress bar grows or shrinks). For updating the view I followed this tutorial: https://dippnerd.com/swiftui-timer-ui-refresh, but for me it is not working. The timer works just fine, but my view does not update. In my root view I do not use the TimerWrapper, I only use it in a secondary view, so I do not have the @EnvironmentObject of TimerWrapper in my root view controller.TimerWrapper:import SwiftUI import Combine class TimerWrapper : ObservableObject { let willChange = PassthroughSubject&lt;TimerWrapper, Never&gt;() var timer : Timer! func start(withTimeInterval interval: Double) { self.timer?.invalidate() self.timer = Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { _ in print("timer fired") self.willChange.send(self) } } }The progressBar view looks as following:import SwiftUI struct MultiplayerBar: View { @EnvironmentObject var timerWrapper: TimerWrapper var body: some View { GeometryReader { geometryReader in Rectangle() .fill(Color.green) Rectangle() .fill(Color.red) .frame(width: getPlayer1Progress(maxWidth: geometryReader.size.width)) .animation(.easeIn) } .frame(height: 200) .cornerRadius(15) .padding() } } struct MultiplayerBar_Previews: PreviewProvider { static var previews: some View { MultiplayerBar() .environmentObject(TimerWrapper()) } }And it is called like this:MultiplayerBar() .shadow(radius: 5) .environmentObject(TimerWrapper())The timer is started in the SceneDelegate.swift file:if let windowScene = scene as? UIWindowScene { let window = UIWindow(windowScene: windowScene) let timer = TimerWrapper() timer.start(withTimeInterval: 1) window.rootViewController = UIHostingController(rootView: ShowTrainingView() .environmentObject(BLEControl.BLESingleton) .environmentObject(UserData())) self.window = window window.makeKeyAndVisible() }Actually I am not quite sure if my approach is right and how I could fix it. Thanks for any help in advance.
Posted
by De Mo.
Last updated
.
Post marked as solved
2 Replies
1.7k Views
When I run the following code, the preview of my view crashes.let data = "123;456;" let dataArr = data.split(separator: ";")The Diagnostics always show the following:argument type 'String.Element' (aka 'Character') does not conform to expected type 'ExpressibleByStringLiteral' let dataArr = data.split(separator: __designTimeString("#9734.[1].[4].[0].value.modifier[0].arg[0].value", fallback: ";"))Does anyone know how to fix this?
Posted
by De Mo.
Last updated
.
Post not yet marked as solved
2 Replies
1.9k Views
I want to have different accounts in an app and save, which one was last used. To do this, I worked with UserDefaults. I also want to share the accounts all over my app in different views. Using EnvironmentObject works just fine for building and running the app, but the preview in canvas does not work.import SwiftUI import Combine final class UserData: ObservableObject { @Published var currentUser: User = userData.first{$0.id == UserDefaults.standard.integer(forKey: "currentUser")}! { didSet { UserDefaults.standard.set(self.currentUser.id, forKey: "currentUser") } } @Published var user = userData }import SwiftUI struct ShowTrainingView: View { @State var showAccounts = false @EnvironmentObject var userData: UserData var body: some View { NavigationView { Text("") .navigationBarTitle("Trainieren") .navigationBarItems(trailing: Button(action: { self.showAccounts.toggle() print("button pressed") }) { Image(systemName: "person") .imageScale(.large) }) } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ShowTrainingView() .environmentObject(UserData()) } }Does anyone know how to fix this?
Posted
by De Mo.
Last updated
.
Post marked as solved
1 Replies
7.4k Views
I want to add a shadow to my CollectionViewCell, but the following code doesn't work.override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -&gt; UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! myCell // Configure the cell cell.layer.cornerRadius = 15.0 cell.layer.masksToBounds = true cell.layer.borderWidth = 0.0 cell.backgroundView?.layer.shadowColor = UIColor.black.cgColor cell.backgroundView?.layer.shadowRadius = 5 cell.backgroundView?.layer.shadowOpacity = 1 cell.backgroundView?.layer.shadowOffset = CGSize(width: 0, height: 0) return cell }I also tried:cell.layer.shadowColor = UIColor.green.cgColor cell.layer.shadowRadius = 5 cell.layer.shadowOpacity = 1 cell.layer.shadowOffset = CGSize(width: 0, height: 0)I don't get an error, but no shadow occurs.
Posted
by De Mo.
Last updated
.
Post not yet marked as solved
1 Replies
1k Views
I am trying to use a CollectionViewCell with a StackView inside. As long as I don't add constraints, everything seems to work just fine, only the stack view isn't aligned. As soon as I add constraints, an error occurs due to missing constraints, but clicking on the "add missing constraints" button doesn't do anything. I solved my problem by adding a view to the cell and put the StackView inside, but I don't understand why it doesn't work without the view.
Posted
by De Mo.
Last updated
.