When using MKMapView within SwiftUI in MacOS, via NSViewRepresentable and a Coordinator, the are several console messages per second "CVDisplayLinkSetPaused", alternating between [TRUE]and [FALSE] when displaying a poly line and/or annotations. This is possibly preventing NSClickGestureRecognizer from working correctly, although that's probably another, developer (my), issue. These console messages have only occurred in the last two Mac OS beta releases, the last being 21D5039d. Even if these messages are not an indication of a problem, they are very distracting and annoying - taking up so much time and space in the logs.
Feedback submitted: FB9845486
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
SwiftUI Map() doesn't provide a way of changing mapType from .standard. Some older (1yr+) StackOverflow posts claim being able to set mapType by using a custom initialiser or an extension, but neither approach seems to work for my needs and set up (Swift 5, iOS 15 beta, Xcode 13).
When I use .onAppear() { MKMapView.appearance().mapType = mapStyle}, where mapStyle is a var of the View, the style is set (e.g. to .hybrid) successfully on the first invocation of the view (the map) but not subsequent ones, which are as .standard. I can't think of any way of solving this.
I could use MapKit with UIViewRepresentable, which I've done a few times before with other projects, but it'd be nice to use "pure" SwiftUI.
Any ideas?
Cheers, Michaela
PS - the reason for wanting satellite or hybrid is that I often need to return to a location in a forest area with poor, or non existent, trail mapping.
Most examples, including within documentation, of using CoreML with iOS involve the creation of the Model under Xcode on a Mac and then inclusion of the Xcode generated MLFeatureProvider class into the iOS app and (re)compiling the app. However, it’s also possible to download an uncompiled model directly into an iOS app and then compile it (background tasks) - but there’s no MLFeatureProvider class. The same applies when using CreateML in an iOS app (iOS 15 beta) - there’s no automatically generated MLFeatureProvider. So how do you get one? I’ve seen a few queries on here and elsewhere related to this problem, but couldn’t find any clear examples of a solution. So after some experimentation, here’s my take on how to go about it:
Firstly, if you don’t know what features the Model uses, print the model description e.g. print("Model: ",mlModel!.modelDescription). Which gives Model:
inputs: (
"course : String",
"lapDistance : Double",
"cumTime : Double",
"distance : Double",
"lapNumber : Double",
"cumDistance : Double",
"lapTime : Double"
)
outputs: (
"duration : Double"
)
predictedFeatureName: duration
............
A prediction is created by guard **let durationOutput = try? mlModel!.prediction(from: runFeatures) ** ……
where runFeatures is an instance of a class that provides a set of feature names and the value of each feature to be used in making a prediction. So, for my model that predicts run duration from course, lap number, lap time etc the RunFeatures class is:
class RunFeatures : MLFeatureProvider {
var featureNames: Set = ["course","distance","lapNumber","lapDistance","cumDistance","lapTime","cumTime","duration"]
var course : String = "n/a"
var distance : Double = -0.0
var lapNumber : Double = -0.0
var lapDistance : Double = -0.0
var cumDistance : Double = -0.0
var lapTime : Double = -0.0
var cumTime : Double = -0.0
func featureValue(for featureName: String) -> MLFeatureValue? {
switch featureName {
case "distance":
return MLFeatureValue(double: distance)
case "lapNumber":
return MLFeatureValue(double: lapNumber)
case "lapDistance":
return MLFeatureValue(double: lapDistance)
case "cumDistance":
return MLFeatureValue(double: cumDistance)
case "lapTime":
return MLFeatureValue(double: lapTime)
case "cumTime":
return MLFeatureValue(double: cumTime)
case "course":
return MLFeatureValue(string: course)
default:
return MLFeatureValue(double: -0.0)
}
}
}
Then in my DataModel, prior to prediction, I create an instance of RunFeatures with the input values on which I want to base the prediction:
var runFeatures = RunFeatures()
runFeatures.distance = 3566.0
runFeatures.lapNumber = 1.0
runFeatures.lapDistance = 1001.0
runFeatures.lapTime = 468.0
runFeatures.cumTime = 468.0
runFeatures.cumDistance = 1001.0
runFeatures.course = "Wishing Well Loop"
NOTE there’s no need to provide the output feature (“duration”) here, nor in the featureValue method above but it is required in featureNames.
Then get the prediction with guard let durationOutput = try? mlModel!.prediction(from: runFeatures)
Regards,
Michaela
Mac Catalyst treats a SwiiftUI .sheet View as compact, even though there is as much horizontal space in the view as on a physical iPad. The outcome of this is that, with an iPhone, iPad, Catalyst app, abbreviated HStacks that I use for the iPhone version also appear on the Catalyst version, unless I use #if targetEnvironment(macCatalyst)
A few months back a Stack Overflow user complained that a Catalyst popover (UIKit) was reporting as .regular and should be .compact. Apple agreed it was a bug. However, in my case (SwiftUI sheet), it doesn't make sense to regard a Catalyst SwiftUI sheet as compact when there is as much space available as on a physical iPad.
Regards to all, Michaela
I already have a working app, using SwiftUI Canvas, for charting sensor milliVolt data at a frequency of 130Hz, so thought I'd see how SwiftUI Charts compared for ease of implementation. Charts is much easier to implement, saving the tedium of scaling and label context placement. However, creating the AxisMarks.Values was a problem because the stride-by method with Calendar.Component has .second as the smallest unit, and I need deciSecond. I tried some other inbuillt options, e.g. desiredCount, but no joy.
After a while I realised that I can create my own values array using a function, so here it is (hoping that this helps someone, somewhere, sometime):
struct ChartView: View {
var chartData : [DataPoint] // An array of CoreData objects with timeStamp and milliVolt attributes
let xSecStyle = StrokeStyle(lineWidth: 1.0)
let xDeciSecStyle = StrokeStyle(lineWidth: 0.5)
...
// The .chartAxis code within Chart in body
.chartXAxis {
AxisMarks(values: deciSecValues) { value in
if Double(value.index).remainder(dividingBy: 10.0) == 0.0 {
// show the second-gridline as wider and display the time label
AxisGridLine(stroke:xSecStyle)
.foregroundStyle(.orange)
AxisValueLabel(format: .dateTime.minute().second(),centered: false)
} else {
AxisGridLine(stroke:xDeciSecStyle)
.foregroundStyle(.orange)
}
}
}
.....
// The func for creating the X Axis Marks
private var deciSecValues : [Date] {
var xDates = [Date]()
if chartData.isEmpty { return xDates }
let deciSecs = (Int(chartData.last!.timeStamp!.timeIntervalSince(chartData.first!.timeStamp!)) + 1) * 10
for i in stride(from: 0, to: deciSecs, by: 1) {
let newTime = Double(i) / 10.0
xDates.append(chartData.first!.timeStamp!.addingTimeInterval(newTime))
}
return xDates
}
Regards, Michaela
I'm devloping an iOS App for the Polar H7 and H10 Heart Rate sensors and it's crucial that the App monitors the attached device's battery level.For ayone who needs to get the battery level from a BLE device (if it supports such), the Battery Service UUID is 0x180F and the battery level characterisitc UUID is 0x2A19, reporting a one byte value with the battery level as a percentage (UInt8). Details are at https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.battery_service.xmlIn my Swift 3 code, having discovered the Service and the Characteristic (2A19), I do a peripheral.readValue(for: battChar) then a peripheral.setNotifyValue(true, for: battChar). The value is then provided in the didupdatevalue for characterisitc function. Not surprisingly, my Polar devices do not constantly update the battery status but must be interrogated from time to time using the peripheral.readvalue(for: ...) function.I hope this helps someone, somewhere, sometime. 🙂
The new TabularData framework in iOS 15, MacOS 12 and watchOS 8 opens up opportunities for easier, more efficient ingestion of data (and for ML possibilities). However, it does not appear to be possible to directly use a DataFrame's rows for a List or ForEach in SwiftUI: the compiler gives an error that the rows do not conform to RandomAccessCollection Protocol. The documentation for Rows does not state compliance with such, even through there are methods which inherit from the protocol.
Using a separate iteration to extract each Row (as a DataFrame.Row) from the DataFrame into a new array works. I make this array identifiable by using the row.index as the id. However, if the DataFrame is large this adds considerably to storage and processing overheads.
Any thoughts on directly using the DataFrame's Rows in SwiftUI?
The TabularData DataFrame writeCSV method formats Double (and possibly Integer) numbers that are >= 1000 with a comma thousands separator and surrounds the output in double quotes. Numbers less than 1000 are not double-quoted. If the resulting CSV file is then read by DataFrame contentsOfCSVFile an error is thrown, i.e. a type mismatch. This happens irrespective of whether the types option is set in the CSV read, or not.
There is no option in DataFrame writeCSV to specify no thousands separator, nor any other obvious way of preventing the double-quoting.
Currently, I "fix" the problem by reading the CSV in Numbers, setting the faulty column(s) to Numeric then exporting back to CSV.
Any thoughts on preventing the issue in the first place?
It seems that a DataFrame (TabularData framework) can be used in CreateML, instead of an MLDataTable - which makes sense, given the description of the TabularData API. However, there are differences.
One is that when using a DataFrame, the randomSplit method creates a tuple of DataFrame slices, which cannot then be used in MLLinearRegressor without first converting back to DataFrame (i.e. initialising a new DataFrame with the required slice). Using an MLDataTable as the source data, the output from randomSplit can be used directly in MLLinearRegressor.
I'm interested to hear of any other differences and whether the behaviour described above is a feature or a bug.
TabularData seems to have more features for data manipulation, although I haven't done any systematic comparison. I'm a bit puzzled as to why there are 2 similar, but separate, frameworks.
According to the documentation for DateComponentsFormatter UnitsStyle .abbreviated https://developer.apple.com/documentation/foundation/datecomponentsformatter/unitsstyle, this style (abbreviated) should create a string like “9h 41m 30s”. In some circumstances, eg MacOS target with import Foundation, the result is "9h 41min. 30s.", which is a sort-of mix between .brief and .abbreviated.
In my SwiftUI multi-platform app (MacOS & iOS) the incorrect (mixed) style is generated for both platforms. Using Playground, the mixed formatting occurs when the platform is set to MacOS, but not iOS with either import UIKit or import Foundation.
Is this a bug, or a "featured" difference between MacOS and iOS?
My multi-platform function is
import Foundation
public func strDuration(_ duration: TimeInterval, style: DateComponentsFormatter.UnitsStyle = .abbreviated) -> String {
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.hour, .minute, .second]
formatter.unitsStyle = style
formatter.maximumUnitCount = 3
return formatter.string(from: duration) ?? "n/a"
}
Regards, Michaela
I'm developing a SwiftUI multi-platform, multi-user app for family budget management (not for the App Store) using CoreData and iCloud with NSPersistentCloudKitContainer.
I use manual Codegen in Xcode to generate the CoreData entity classes, then add extensions for computed properties. These are in my DataModel (ViewModel), which is in an included framework. All data processing is done in the data model.
All's working fine in the SwiftUI Views, except for one entity - 'Transaction', which throws a compiler error "'Transaction' is ambiguous for type lookup in this context". Some SO posts say to use the App Name as a prefix to the type, but this doesn't work.
What does solve it, in this case, is to use the name of the Framework (Library) holding the type definition:
import SwiftUI
import OurMoneyLib // my framework holding the DataModel and CoreData entity classes
struct TransactionRow: View {
let appAPI = AppAPI()
var transaction : OurMoneyLib.Transaction
var body: some View { ......
Why this one entity throws an error, I know not - but it's fixed!
I hope this helps someone, somewhere, sometime.
Cheers, Michaela
I have a wireless stateless-switch within my private network (LAN) which transmits HTTP posts to a configured URL (e.g. an always-on MacMini) about the switch's state. Upon receipt of a post, my MacOS app will then take appropriate action. No response to the sender is required. The frequency of posts will be minimal ( a few per day), but require immediate attention when received. The LAN is protected from external misuse by a secure gateway.
I'd appreciate any suggestions for a lightweight solution (i.e. not a full-blown web-server), either as an overview of methods or sample source (e.g. on GitHub).
Regards, Michaela
For some time now Apple has been referring to iPadOS (eg in https://developer.apple.com/download/ ), but there is no compiler directive in Xcode to check for iPadOS - even though Xcode now has supported destinations for iPhone, iPad and Mac (catalyst).
I have a couple of use cases where I'd really prefer to include/exclude large chunks of code (frameworks) based on whether the device is an iPad or an iPhone, not just because of the different user-interface characteristics - which can be accommodated using the UIUserInterfaceIdiom.
Regards,
Michaela
I'm developing a SwiftUI, CoreData / CloudKit App with Xcode 16.2 & Sequoia 15.2. The main CoreData entity has 20 NSManaged vars and 5 derived vars, the latter being computed from the managed vars and dependent computed vars - this somewhat akin to a spreadsheet. The data entry/updating Form is complex for each managed var because the user needs to be able to enter data in either Imperial or Metric units, and then switch (by Button) between units for viewing equivalents. This has to happen on an individual managed var basis, because some source data are in Imperial and others Metric.
Consequently, I use a generalised SubView on the Form for processing the managed var (passed as a parameter with its identity) and then updating the CoreData Entity (about 100 lines of code in total): i.e. there are 20 uses of the generalised SubView within the Main Form. However, none of the SubViews triggers an update of the managed var in the Form, nor computations of the derived vars. On initial load of the app, the CoreData entity is retrieved and the computations happen correctly: thereafter not.
No technique for refreshing either View works: e.g. trigger based on NSManagedObjectContextDidSave; nor does reloading the CoreData entity after Context Save (CoreData doesn't recognise changes at the attribute level anyway). If the SubView is removed and replaced with code within the Form View itself, then it works. However, this will require about 40 @State vars, 20 onCommits, etc - so it's not something I'm keen to do.
Below is a much-simplified example of the problem.
Form{
Section(header: Text("Test Record")){
Text(testRec.dateString ?? "n/a")
TextField("Notes",text:$text)
.onSubmit{
testRec.notes = text
dataStore.contextSave()
}
//DoubleNumberEntry(testRec: testRec) - doesn't work
TextField("Double",value:$numDbl,format: .number)
// This works
.onSubmit{
testRec.dblNum = numDbl
dataStore.contextSave()
}
TextField("Integer",value: $numInt,format: .number)
.onSubmit{
testRec.intNum = Int16(numInt)
dataStore.contextSave()
}
Text(String(format:"%.2f",testRec.computation))
Section(header: Text("Computations")) {
Text(String(format:"%.2f",testRec.computation))
Text(String(format:"%.2f",testRec.anotherComputation))
}
}
}
A much simplified version of my NSManaged var entry/updating.
struct DoubleNumberEntry: View {
let dataStore = MainController.shared.dataStore
var testRec : TestRec
@State private var numDbl: Double
init(testRec: TestRec) {
self.testRec = testRec
self.numDbl = testRec.dblNum
}
var body: some View {
TextField("Double",value:$numDbl,format: .number)
.onSubmit{
testRec.dblNum = numDbl
dataStore.contextSave()
}
}
}
I'd appreciate any offered solution or advice.
Regards, Michaela
With MacOS Sequoia 15.4 Beta (24E5206s) and Xcode 16.3 beta (16E5104o), Predictive Code Completion no longer works. Prior to the update, (as of yesterday) completion worked under Xcode 16.2 and MacOS 15.3 Beta. The models are already loaded.
So far, I've found the Predictive Completion to be useful in some situations (eg multiple cases in a switch), variably reliable in others (eg code suggestions in a CoreData stack) and downright wrong & annoying in others (eg referring to functions / modules that don't exist).
Regards, Michaela