Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I have cloudkit records that are downloaded, each with a location property (lat & long). When I set each record to my MKAnnotation Class in a for loop, a CLLocationCoordinate2D property, and run... I receive the error as the title states.
This is what I receive -
Why am I even dealing with an NSValue property? I only have coordinates in my class and CkRecord.
let location = res.value(forKey: "Location")
print("RUN PLEASE")
self.pin = AnnotationPin(title: res.value(forKey: "Name") as! String, subtitle: "Address", theCoordinates: location as! CLLocationCoordinate2D, theWeb: "https://google.com")
CLLocation and CLLocationCoordinate2D are different types which are not related. However CLLocation has a coordinate property.
Cast location to CLLocation and use coordinate
let location = res.value(forKey: "Location") as! CLLocation
self.pin = AnnotationPin(title: res.value(forKey: "Name") as! String,
subtitle: "Address",
theCoordinates: location.coordinate,
theWeb: "https://google.com")
Related
I am attempting to include a function in a Predicate definition. Is this possible?
Let's say you have a Core Data entity of Places with attributes for
latitude and longitude.
I would like to add annotations to a mapview of those Places within a
specified distance from the user location. I can, of course, loop through the entire database and calculate the distance between each Place and the
user location but I will have about 35000 places and it would seem that
it would be more efficient to have a predicate in the
fetchedResultsController setup.
I tried the code below but I receive an error message of "Problem with
subpredicate BLOCKPREDICATE(0x2808237b0) with userInfo of (null)"
func myDistanceFilter(myLat : CLLocationDegrees, myLong : CLLocationDegrees, cdLat : CLLocationDegrees, cdLong : CLLocationDegrees) -> Bool {
let myLocation = CLLocation(latitude: myLat, longitude: myLong)
let cdLocation = CLLocation(latitude: cdLat, longitude: cdLong)
if myLocation.distance(from: cdLocation) < 5000.0 {
return true
} else {
return false
}
}//myDistancePredicate
And inside the fetchedResultsController:
let distancePredicate = NSPredicate {_,_ in self.myDistanceFilter(myLat: 37.774929, myLong: -122.419418, cdLat: 38.0, cdLong: -122.0)}
If it is possible to have a block/function inside a predicate how do you get a reference to an attribute for the entity object being evaluated?
Any guidance would be appreciated.
An additional observation for anyone else struggling with a similar issue.
Considering the suggestions of pbasdf and Jerry above, at least in my case, there is no reason why a region has to be round. I'll craft a name indicating a nearly rectangular area. I ran some tests with latitude and longitude values. These latitude and longitude values can be scaled to a rectangle enclosing a circular radius specified by the user. One degree of latitude is about 69 miles and one degree of longitude at the latitude of Chicago is about 51 miles. I used the following:
var myUserLatitude : CLLocationDegrees!
var myUserLongitude : CLLocationDegrees!
In the init file for the view:
guard let userLatitude = locationManager.location?.coordinate.latitude else {return}
guard let userLongitude = locationManager.location?.coordinate.longitude else {return}
myUserLatitude = userLatitude
myUserLongitude = userLongitude
Inside the fetchedResultsController variable creation:
let latitudeMinPredicate = NSPredicate(format: "latitude >= %lf", myUserLatitude - 1.0)
let latitudeMaxPredicate = NSPredicate(format: "latitude <= %lf", myUserLatitude + 1.0)
let longitudeMinPredicate = NSPredicate(format: "longitude >= %lf", myUserLongitude - 1.0)
let longitudeMaxPredicate = NSPredicate(format: "longitude <= %lf", myUserLongitude + 1.0)
var compoundPredicate = NSCompoundPredicate()
compoundPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [anotherUnrelatedPredicate,latitudeMinPredicate,latitudeMaxPredicate,longitudeMinPredicate, longitudeMaxPredicate])
fetchRequest.predicate = compoundPredicate
Obviously I will create another property to scale the 1.0 value per the user desired region. Initial tests seem to work and best of all I can't believe how fast it it. Literally, the tableView is populated by the time the viewController segues to the enclosing mapView.
Well, yes it is possible. NSPredicate does have +predicateWithBlock: and init(block:).
However if you scroll down on that page you see the bad news:
Core Data supports block-based predicates in the in-memory and atomic stores, but not in the SQLite-based store.
So, whether you use an in-memory store, or do the filtering in code, either way you need to bring these 35,000 items into memory, and performance of a brute force approach will be poor.
There is a point of complexity at which SQL is no longer appropriate – you get better performance with real code. I think your requirement is far beyond that point. This will be an interesting computer science project in optimization. You need to do some pre-computing, analagous to adding an index to your database. Consider adding a region attribute to your place entities, then write your predicate to fetch all places within the target location's region and all immediate neighbors. Then filter through those candidates in code. I'm sure this has been done by others – think of cells in a cell phone network – but Core Data is not going to give you this for free.
I am making a single view application in Xcode, with Google Map SDK. I have followed instructions online and my application can successfully load the google map view. I have also enabled myLocation, so that myLocation button shows on the map view.
I understand that clicking the myLocation button will change the camera location automatically, but I'm wondering what I should do to use the data of myLocation (say to add a marker or add a path node)?
I've tried directly accessing mapView.myLocation, for example
let lat = mapView.myLocation?.coordinate.latitude
let long = mapView.myLocation?.coordinate.longitude
path.addCoordinate(CLLocationCoordinate2D(latitude: lat!, longitude: long!))
However, this will crash the applicaton and throw:
fatal error: unexpectedly found nil while unwrapping an Optional value
What does this error message mean and how should I resolve this?
The error says that myLocation property of mapView is nil. You should check if there is a value before accessing it.
if let myLocation = mapView.myLocation {
let lat = myLocation.coordinate.latitude
let long = myLocation.coordinate.longitude
path.addCoordinate(CLLocationCoordinate2D(latitude: lat, longitude: long))
}
Also verify why myLocation is nil. It might be that the user didn't allow location services.
This will not give any errors:
let lat = mapView.myLocation?.coordinate.latitude ?? give any value of latitude
let long = mapView.myLocation?.coordinate.longitude ?? give any value of longitude
I would like to provide multiple MapKit annotations (pins) in Xcode 7.0.1 but have no idea how to, I've created one annotation:
let location = CLLocationCoordinate2DMake(50.714141, -1.874704)
let annotation = MKPointAnnotation()
annotation.coordinate = location
annotation.title = "Bournemouth Pier"
mapView.addAnnotation(annotation)
It seems I can't just copy and paste this code with different titles and coordinates which is really annoying and quite frankly stupid. (you can tell how annoyed I am) any help would be appreciated cheers.
You definitely can add multiple annotations this way. Make sure you instantiate a new MKPointAnnotation for each one, though.
For example:
var location = CLLocationCoordinate2DMake(50.714141, -1.874704)
var annotation = MKPointAnnotation()
annotation.coordinate = location
annotation.title = "Bournemouth Pier"
mapView.addAnnotation(annotation)
location = CLLocationCoordinate2DMake(51.714141, -2.874704)
annotation = MKPointAnnotation()
annotation.coordinate = location
annotation.title = "Gwernesney"
mapView.addAnnotation(annotation)
If you're still having trouble adding multiple annotations, please edit your question, showing us how you are trying to do that. You've shown an attempt at adding a single annotation, but not how you've attempted to add multiple ones.
I'm a complete newbie using Swift and I'm having a headache trying to do something that should be quite straightforward.
I have an object Place with a variable of type Double called distance. I'm using the following code to store the distance between the user location and some other locations:
var obj = res as Place
let loc = CLLocation(latitude: obj.location.lat, longitude: obj.location.lng)
let dist = CLLocation.distanceFromLocation(loc)
obj.distance = dist // ERROR
The last line shows me an error saying "CLLocationDistance is not convertible to 'Double'". As far I know, CLLocationDistance should be a Double. I've tried to cast that value to double and float using
Double(dist)
and
obj.distance = dist as Double
but nothing seems to work. I would appreciate any help.
The reason this is occurring boils down to the following line:
let distance = CLLocation.distanceFromLocation(loc)
This is not doing what you think it's doing. distanceFromLocation is an instance method, but you are calling it as a class method. Unlike ObjC, Swift allows this, but what you're actually getting back is not a CLLocationDistance but a function with the following type signature: CLLocation -> CLLocationDistance. You can verify this by adding in the type annotation yourself:
let distance: CLLocation -> CLLocationDistance = CLLocation.distanceFromLocation(loc)
This is called partial application and is outside the scope of my answer, except to note that the first parameter of the function assigned to distance would be the implicit self when called as an instance method.
The fix is simple:
let distance = loc.distanceFromLocation(loc)
Then everything will work as you desire, at least from the perspective of the type system, because this properly returns a CLLocationDistance, which is substitutable for Double.
You need two objects of CLLocation with two different locations
Like as fromLocation and toLocation
Then you will get distance in
let distance = fromLocation.distanceFromLocation(toLocation)
An Example of Code for distance between old and new location :
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
if let firstLocation = locations.first as? CLLocation
{
mapView.setCenterCoordinate(firstLocation.coordinate, animated: true)
let region = MKCoordinateRegionMakeWithDistance(firstLocation.coordinate, 1000, 1000)
mapView.setRegion(region, animated: true)
if let oldLocation = oldLocation {
let delta: CLLocationDistance = firstLocation.distanceFromLocation(oldLocation)
totalDistane += delta
updateDistanceLabel()
}
oldLocation = firstLocation
}
}
I am working on an app for iOS 7 and I need to find the location of the user and then check to see what other users are also at that same location. I need it to update as soon as the user opens the app as well as update every so often and will display the users at the same location. I have looked at the available examples, but there doesn't seem to be enough on this using Parse. Can anyone give me any help on how to go about doing this, or if anyone knows of some examples similar to what I'm trying to do I would greatly appreciate it. Thanks in advance!
You need to break your problem down and tackle the various pieces -
Obtain the user's location when the app opens and periodically
The Location and Maps programming guide is a good starting point. You can use CLLocationManager to obtain your initial location and you can register for the significant location change event to get updates periodically, even when your app isn't running. Apple has example code plus there are plenty of other examples out there - Just search using "Core Location examples"
Store the user's location in your Parse database
There are examples and documentation on Parse.com showing how to do this. You can also provide a web service that allows your app to query the database for other users at the same location
Identify other users at the same location when your app isn't running
You can use Parse background jobs to trawl your database, match user locations and send push notifications to your users. Again there are examples on Parse.com showing how to set up background jobs and push notifications
this may help this will get your current location then save to parse, its just a matter of querying parse to pull the data down
func locationManager(manager: CLLocationManager!, didUpdateLocations
locations: [AnyObject]!) {
var userLocation : CLLocation = locations[0] as! CLLocation
var latitude = userLocation.coordinate.latitude
var longitude = userLocation.coordinate.longitude
var latDelta : CLLocationDegrees = 0.01
var lonDelta : CLLocationDegrees = 0.01
var span : MKCoordinateSpan = MKCoordinateSpanMake(latDelta,
lonDelta)
var location : CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitude, longitude)
var region : MKCoordinateRegion = MKCoordinateRegionMake(location, span)
self.mapView.setRegion(region, animated: true)
let testObject = PFObject(className: "User")
let currentPoints = PFGeoPoint(latitude: latitude, longitude: longitude)
testObject.setValue(currentPoints, forKey: "currentLocation")
testObject.saveInBackgroundWithBlock { (success: Bool, error: NSError?) -> Void in
if (success) {
dispatch_async(dispatch_get_main_queue()) {
println("added to parse")
}
} else {
println(error)
}
}
}