What I am trying to accomplish:
Navigate to MapView defined in ProfileMapView. - This works
In ProfileMapView, when calloutAccessoryControlTapped method is called Navigate from ProfileMapView when to another view: ProfileDetailsView- This is does not work
//Calling ProfileMapview like this:
@State var pins = [GpsData.MyEndPt]()
ProfileMapView(locationPins: $pins)
// ProfileMapView defined
struct ProfileMapView: View {
@Environment(\.managedObjectContext) private var viewContext
@Environment(\.dismiss) var dismiss
@State var tracking:MapUserTrackingMode = .follow
@Environment(\.presentationMode) var presentationMode
@Binding var locationPins: [GpsData.MyEndPt]
var body: some View {
TabView {
NavigationView {
ZStack {
VStack (alignment: .leading){
MapView(locationPins: $locationPins)
.ignoresSafeArea()
}
}
//.edgesIgnoringSafeArea(.all)
.safeAreaInset(edge: .bottom) {
Color.clear
.frame(height: 0)
.background(.white)
}
}
}
struct MapView: UIViewRepresentable {
@Binding var locationPins: [GpsData.MyEndPt]
func makeUIView(context: Context) -> MKMapView {
//...
}
func updateUIView(_ uiView: MKMapView, context: Context) {
//...
}
func makeCoordinator() -> MapViewDelegate{
var del = MapViewDelegate()
del.addEndPoints(endPoints: locationPins)
return del
}
class MapViewDelegate: MKMapView, MKMapViewDelegate {
let PINID:String = "MyEndPoint"
var mylocationPins: [GpsData.MyEndPt] = []
@State var locationId: String?
@State var providerType: String?
public func addEndPoints(endPoints: [GpsData.MyEndPt]) {
self.mylocationPins = endPoints
self.removeAnnotations(endPoints)
self.addAnnotations(endPoints)
self.showAnnotations(endPoints, animated: true)
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
var mPin: MKMarkerAnnotationView? = nil
let subtitleView = UILabel()
for pin in self.mylocationPins {
if (mPin == nil ) {
mPin = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: PINID)
mPin?.canShowCallout = true
} else{
mPin?.annotation = annotation
}
mPin?.rightCalloutAccessoryView = UIButton(type: UIButton.ButtonType.detailDisclosure)
subtitleView.text = "Target: "
subtitleView.text! += String(pin.target)
}
mPin!.detailCalloutAccessoryView = subtitleView
return mPin!
}
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
DispatchQueue.main.async {
if let thumbnailImageButton = view.leftCalloutAccessoryView as? UIButton,
let url = (view.annotation as? GpsData.MyEndPt)?.thumbnailUrl
{
print("URL: \(url)")
do{
let imageData: Data = try Data(contentsOf: url as URL)
let image = UIImage(data: imageData)
thumbnailImageButton.setImage(image, for: UIControl.State.normal)
}catch{
print("Unable to load image data: \(error)")
}
}
}
}
//MARK:- delegate method
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == view.rightCalloutAccessoryView {
mapView.deselectAnnotation(view.annotation, animated: true)
for detail in self.mylocationPins {
locationId = detail.locationId
providerType = detail.providerType
NavigationLink(value: control) {
ProfileDetailsView(locationId: $locationId, providerType: $providerType)
}
break
}
}
}
}
}
}
ProfileDetailsView defined like this:
@StateObject var manager = LocationManager()
@State var tracking:MapUserTrackingMode = .follow
@Environment(\.presentationMode) var presentationMode
@Binding var locationId: String?
@Binding var providerType: String?
var body:some View {
VStack (alignment: .leading){
Text("Details here...")
Button {
}
label: {
Text("Share")
.foregroundColor(.blue)
}
.buttonStyle(.bordered)
Button {
}
label: {
Text("Update consumption")
.foregroundColor(.blue)
}
.buttonStyle(.bordered)
}
}
}
I get warning: "Accessing State's value outside of being installed on a View. This will result in a constant Binding of the initial value and will not update." inside ProfileMapView line wheer I define @Binding var locationPins: [GpsData.MyEndPt]. That value is being passed into ProfileMapView - so I dont know why then warning.
However, ProfileMapView gets called, the mapview is displayed and the marker pin appears and when I click on the disclosure the navigation to other view ProfileDetailsView does not work. I tried NavigationStack and could not make it work because it threw lot of errors. How to fix the code in calloutAccessoryControlTapped method, so I can navigate to other view: ProfileDetailsView. I have spent a week on this trying various things but it hasn't worked.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
Trying to get weather data for a specific location and specific timezone. Generated Service identifier and Private Key, from Apple developer site.
Then Generated public key
Generated jwt token from jwt.io by keying in the payload, header, public, and private key.
Header
{
"alg" : "ES256", // predefined
"kid" : “keyid” , // key id created for WeatherKit
"id" : “developer_team_account_id.com.company_name.MyWeatherKit,
"typ" : "JWT"
}
Payload
{
"iat" : 1710117942,
"exp" : 1710204342,
"iss" : "developer_team_account_id",
"sub" : "com.company_name.MyWeatherKit
}
I
Then call this function:
func getWeatherData(requestId: String,
latitudeStr: String,
longitudeStr: String,
completion: @escaping (Bool) -> () ){
var country = "US"
var language = "en"
var tz = "CST"
let jwtToken = "token here...."
let urlString:String = "https://weatherkit.apple.com/api/v1/availability/" + language + "/" + latitudeStr + "/" + longitudeStr + "?" + "country=" + country + "&" + "timezone=" + tz
print("Apple weather urlString: \(urlString)")
let weatherURL = URL(string: urlString)
var request = URLRequest(url: weatherURL!)
request.httpMethod = "GET"
request.setValue("Bearer \(jwtToken)", forHTTPHeaderField: "Authorization")
let dataTask = URLSession.shared.dataTask(with:weatherURL!) { [self] responseData, response, error in
do {
print(response as Any)
print(error as Any)
if let data = responseData {
try DispatchQueue.main.sync { [unowned self] in
let decoder = JSONDecoder()
let jsonData = try decoder.decode(Top.self, from: data)
// parse data here
print(jsonData)
completion(true)
}
}
}
catch {
print("error: \(error.localizedDescription)")
completion(false)
}
}
dataTask.resume()
}
Gives response with code 403
Optional(<NSHTTPURLResponse: 0x280cbcf00> { URL: https://weatherkit.apple.com/api/v1/availability/en/29.928894042968750/-95.607747517125430?country=US&timezone=CST } { Status Code: 403, Headers {
"Access-Control-Allow-Origin" = (
"*"
);
Connection = (
close
);
"Content-Security-Policy" = (
"default-src 'self';"
);
Date = (
"Tue, 12 Mar 2024 02:52:18 GMT"
);
Server = (
Apple
);
"Strict-Transport-Security" = (
"max-age=31536000; includeSubdomains"
);
"X-Cache" = (
"TCP_MISS from a23-38-189-78.deploy.akamaitechnologies.com (AkamaiGHost/11.4.3-54729273) (-)"
);
"X-Content-Type-Options" = (
nosniff
);
"X-Frame-Options" = (
SAMEORIGIN
);
"X-REQUEST-ID" = (
"bac7e5dc-c5fd-6f85-263b-8f59b169cd2f"
);
"X-XSS-Protection" = (
"1; mode=block"
);
} })
The URL I am passing is : https://weatherkit.apple.com/api/v1/availability/en/29.928894042968750/-95.607747517125430?country=US&timezone=CST
Am I calling the wrong URL? Or is Apple weather service down? I am at a loss to understand. I need some help and guidance
when I click on a mapview pin, a PopupView comes up with some text and a button. I want to be able to navigate to another DetailsView by clicking on the button display in the popup, the button is embedded inside NavigationLink. But clicking on the button nothing happens. How to navigate from button click?
struct MyMapView: View {
@State var position: MapCameraPosition = .automatic
@State var showCallout: Bool = false
@State var selected: PinAnnotation?
@Binding var locationPins: [PinAnnotation]
@State private var toggler = false
var body: some View {
Map(position: $position) {
ForEach(locationPins, id: \.self) { result in
Annotation(result.title!, coordinate: result.coordinate) {
ZStack {
Image(systemName: "mappin.circle.fill")
.resizable()
.scaledToFit()
.frame(width: 30, height: 30)
.onTapGesture {
selected = result
toggler.toggle()
}
.foregroundStyle(.white, .purple)
if selected == result && toggler {
PopupView(pin: selected)
} else {
EmptyView()
}
}
}
}
}
}
struct PopupView: View {
@State var pin: PinAnnotation?
@State private var select: Int? = 0
var body: some View {
VStack (alignment: .leading) {
HStack {
if let val = pin {
Text(val.text)
.font(.system(size: 12, weight: .light, design: .default))
NavigationLink(destination: DetailsView(), label: {
Button(action: {select = 1}){
Image(systemName: "play.circle")
}
.scaledToFit()
.frame(width: 50, height: 50)
.background(Color.blue)
.foregroundColor(.white)
.clipShape(Circle())
})
} else {
Text("no data")
}
}
// .fixedSize()
}
.scaledToFit()
.foregroundStyle(.purple)
.frame(maxWidth: .infinity)
.background(Color.white)
.cornerRadius(10)
.shadow(radius: 5)
.offset(x: 0, y: -45)
}
}
struct DetailsView: View {
@Environment(\.presentationMode) var presentation
var body: some View {
Group {
Button("Back") {
self.presentation.wrappedValue.dismiss()
}
}
}
}
}
In core-data I have a contact and location entity. I have one-to-many relationship from contact to locations and one-to-one from location to contact. I create contact in a seperate view and save it. Later I create a location, fetch the created contact, and save it while specifying the relationship between location and contact contact and test if it actually did it and it works.
viewContext.perform {
do {
// Set relationship using the generated accessor method
currentContact.addToLocations(location)
try viewContext.save()
print("Saved successfully. Locations count:", currentContact.locations?.count ?? 0)
if let locs = currentContact.locations {
print("📍 Contact has \(locs.count) locations.")
for loc in locs {
print("➡️ Location: \(String(describing: (loc as AnyObject).locationName ?? "Unnamed"))")
}
}
} catch {
print("Failed to save location: \(error.localizedDescription)")
}
}
In my NSManagedObject class properties I have this : for Contact:
@NSManaged public var locations: NSSet?
for Location:
@NSManaged public var contact: Contact?
in my persistenceController I have:
for desc in [publicStore, privateStore] {
desc.setOption(true as NSNumber, forKey:
NSPersistentStoreRemoteChangeNotificationPostOptionKey)
desc.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
desc.setOption(true as NSNumber, forKey: NSMigratePersistentStoresAutomaticallyOption)
desc.setOption(true as NSNumber, forKey: NSInferMappingModelAutomaticallyOption)
desc.setOption(true as NSNumber, forKey: "CKSyncCoreDataDebug") // Optional: Debug sync
// Add these critical options for relationship sync
desc.setOption(true as NSNumber, forKey: "NSPersistentStoreCloudKitEnforceRecordExistsKey")
desc.setOption(true as NSNumber, forKey: "NSPersistentStoreCloudKitMaintainReferentialIntegrityKey")
// Add this specific option to force schema update
desc.setOption(true as NSNumber, forKey: "NSPersistentStoreRemoteStoreUseCloudKitSchemaKey")
}
When synchronization happens on CloudKit side, it creates CKRecords: CD_Contact and CD_Location. However for CD_Location it creates the relationship CD_contact as a string and references the CD_Contact. This I thought should have come as REFERENCE On the CD_Contact there is no CD_locations field at all. I do see the relationships being printed on coredata side but it does not come as REFERENCE on cloudkit. Spent over a day on this. Is this normal, what am I doing wrong here? Can someone advise?
The NSPersistentCloudKitContainer synchronization between core data and
iCloud was working fine with phone 15.1. Connected a new iPhone iOS 15.5, it gives error:
CoreData: debug: CoreData+CloudKit: -[NSCloudKitMirroringDelegate managedObjectContextSaved:](2504): <NSCloudKitMirroringDelegate: 0x28198c000>: Observed context save: <NSPersistentStoreCoordinator: 0x2809c9420> - <NSManagedObjectContext: 0x2819ad520>
2022-12-05 13:32:28.377000-0600 r2nr[340:6373] [error] error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _importFinishedWithResult:importer:](1245): <PFCloudKitImporter: 0x2837dd740>: Import failed with error:
Error Domain=NSCocoaErrorDomain Code=4864 "*** -[NSKeyedUnarchiver _initForReadingFromData:error:throwLegacyExceptions:]: incomprehensible archive (0x53, 0x6f, 0x6d, 0x65, 0x20, 0x65, 0x78, 0x61)" UserInfo={NSDebugDescription=*** -[NSKeyedUnarchiver _initForReadingFromData:error:throwLegacyExceptions:]: incomprehensible archive (0x53, 0x6f, 0x6d, 0x65, 0x20, 0x65, 0x78, 0x61)}
CoreData: error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _importFinishedWithResult:importer:](1245): <PFCloudKitImporter: 0x2837dd740>: Import failed with error:
Error Domain=NSCocoaErrorDomain Code=4864 "*** -[NSKeyedUnarchiver _initForReadingFromData:error:throwLegacyExceptions:]: incomprehensible archive (0x53, 0x6f, 0x6d, 0x65, 0x20, 0x65, 0x78, 0x61)" UserInfo={NSDebugDescription=*** -[NSKeyedUnarchiver _initForReadingFromData:error:throwLegacyExceptions:]: incomprehensible archive (0x53, 0x6f, 0x6d, 0x65, 0x20, 0x65, 0x78, 0x61)}
I go back and try with my old iPhone iOS 15.1, gives same error.