I'm incorporating the HERE SDK into my app. Aside from one simple map setup, all the examples on the HERE website are shown in objective-C, and I'm trying my best to translate them into Swift but it's not working 100% yet. I'm trying to put a route between 2 coordinates onto a map view as per their routing example shown at:
https://developer.here.com/mobile-sdks/documentation/ios/topics/routing.html
The interesting thing is that if I just call for the map everything works, but if I add the routing part I get the following error:
NMAKit FATAL: License Key, App ID, or App Code not set. error on launch which is odd because the credentials are fine! So I think the bug is entirely in my Swift translation.
The instructions in objective-C are very clear:
1. Adopt NMARouteManagerDelegate protocol and create a NMARouteManager:
#interface ClassName : NSObject <NMARouteManagerDelegate>
{
// Setup your class
}
(void)setup
{
Create a NMARouteManager.**
NMARouteManager* routeManager = [NMARouteManager sharedRouteManager];
// Setup delegate
[routeManager setDelegate:self];
}
2. Create an NSMutableArray and add two NMAGeoCoordinates stops:
NSMutableArray* stops = [[NSMutableArray alloc] initWithCapacity:4];
NMAGeoCoordinates* geoCoord1 = [[NMAGeoCoordinates alloc]
initWithLatitude:49.1966286 longitude:-123.0053635];
NMAGeoCoordinates* geoCoord2 = [[NMAGeoCoordinates alloc]
initWithLatitude:49.1947289 longitude:-123.1762924];
[stops addObject:geoCoord1];
[stops addObject:geoCoord2];
3. Create an NMARoutingMode and set its NMATransportMode, NMARoutingType and NMARoutingOption values:
NMARoutingMode* routingMode = [[NMARoutingMode alloc]
initWithRoutingType:NMARoutingTypeFastest
transportMode:NMATransportModeCar
routingOptions:0];
4. Calculate the route:
[routeManager calculateRouteWithStops:stops routingMode:routingMode];
5. To receive the results of the route calculation, implement the NMARouteManagerDelegate protocol method
routeManager:didCalculateRoutes:withError:violatedOptions: in your delegate class.
Note: Routes are returned even if you receive the NMARouteManagerErrorViolatesOptions error. It is up to you to handle these route results that violate routing options.
-(void) routeManager: (NMARouteManager*)routeManager
didCalculateRoutes:(NSArray*)routes
withError:(NMARouteManagerError)error
violatedOptions:(NSArray*)violatedOptions
{
// If the route was calculated successfully
if (!error && routes && routes.count > 0)
{
NMARoute* route = [routes objectAtIndex:0];
// Render the route on the map
mapRoute = [NMAMapRoute mapRouteWithRoute:route];
[mapView addMapObject:mapRoute];
}
else if (error)
{
// Display a message indicating route calculation failure
}
}
And this is what I'm trying to do in Swift:
import UIKit
//I changed the NMARouteManagerDelegate to my original class here
//and couldnt allow NSObject in the class delegation because it conflicts with UIViewController
class TestViewController: UIViewController, NMARouteManagerDelegate {
var mapCircle:NMAMapCircle?
#IBOutlet weak var mapView: NMAMapView!
#IBAction func get_route_action(sender: AnyObject) {
doRouting()
}
let routeManager = NMARouteManager.sharedRouteManager()
func doRouting() {
let geoCoord1 = NMAGeoCoordinates(latitude:41.350949, longitude:-74.182097)
let geoCoord2 = NMAGeoCoordinates(latitude:41.3437502, longitude:-74.1624284)
let stops = [geoCoord1, geoCoord2]
routeManager.calculateRouteWithStops(stops)
}
func routeManager(routeManager: NMARouteManager!, didCalculateRoutes routes: [AnyObject]!, withError error: NMARouteManagerError, violatedOptions: [AnyObject]!) {
print(routes)
print(error)
print(violatedOptions)
guard error == NMARouteManagerError.None else {
print("Route calculation error: \(error)")
return
}
guard let routes = routes, route = routes[0] as? NMARoute else {
print("Route calculation error: no routes")
return
}
let mapRoute = NMAMapRoute(route: route)
// Render the route on the map
mapView.addMapObject(mapRoute)
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
//mapView.useHighResolutionMap = true
var coordinates: NMAGeoCoordinates
coordinates = NMAGeoCoordinates(latitude: 41.350949, longitude: -74.182097)
mapView.zoomLevel = 13.2
mapView.setGeoCenter(coordinates, withAnimation: NMAMapAnimation.Linear)
mapView.copyrightLogoPosition = NMALayoutPosition.BottomCenter
addMapCircle()
}
func addMapCircle() {
if mapCircle == nil {
let coordinates: NMAGeoCoordinates =
NMAGeoCoordinates(latitude: 41.350949, longitude: -74.182097)
mapCircle = NMAMapCircle(geoCoordinates: coordinates, radius: 50)
mapView.addMapObject(mapCircle)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I tried your code, and worked basically for me quite fine.
But I additionally added the credentials in AppDelegate.swift:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
NMAApplicationContext.setAppId(YourAppID, appCode: YourToken, licenseKey: YourKey);
return true;
}
This is critical, since if it's missing, it's throwing exactly the error you get.
Related
I am trying to add my data from my Json file into the application.I want append the Authors name from the Json file into the empty array.
I have added all of the areas that needed to be added when i run the simulation i get an empty array. I need it display the Authors first name on the simulator.
Does anyone know what i need to do to my code to make it work?
My Code :
var AuthorGlobal = [String]()
class ViewController: UIViewController, UITextFieldDelegate{
#IBOutlet weak var DisplayAuthor: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
DisplayAuthor.text="\(AuthorGlobal)"
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated);
Alamofire.request(.GET, "http://178.62.83.50/newsletters.json")
.responseJSON { response in
// print(response.request) // original URL request
// print(response.response) // URL response
// print(response.data) // server data
// print(response.result) // result of response serialization
if let _ = response.result.value {
// print("JSON: \(JSON)")
}
let json = JSON(data: response.data!)
if let Author = json["NewsLetter"][0]["Author"].string {
AuthorGlobal.append(Author)
}
if let LastName = json["NewsLetter"][0]["LastName"].string {
print(LastName)
}
if let ArticleTitle = json["NewsLetter"][0]["ArticleTitle"].string {
//Now you got your value
print(ArticleTitle)
}
if let Author = json["NewsLetter"][1]["Author"].string {
//Now you got your value
print(Author)
}
if let LastName = json["NewsLetter"][1]["LastName"].string {
//Now you got your value
print(LastName)
}
if let ArticleTitle = json["NewsLetter"][1]["ArticleTitle"].string {
//Now you got your value
print ("Article Title: " + (ArticleTitle))
}
}
}
I just tried by putting your json in my file system and loading it locally. Below is my code on Swift 2 and it all worked fine. You might want to check the JSON data coming correctly in your service call. Also, try to compare it line by line with my code to see if you missed out something. Its too late for me to call it a day so bear with me to not pointing out the exact root cause in your code!
var AuthorGlobal = [String]()
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var DisplayAuthor: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// DisplayAuthor.text="\(AuthorGlobal)"
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated);
let filePath = NSBundle.mainBundle().pathForResource("1", ofType: "json")
var fileContents : String = ""
do {
fileContents = try String(contentsOfFile: filePath!, encoding: NSUTF8StringEncoding)
} catch (_) {
}
var json : Dictionary<String,Array<Dictionary<String,String>>> = Dictionary()
do {
json = try NSJSONSerialization.JSONObjectWithData(fileContents.dataUsingEncoding(NSUTF8StringEncoding)!, options:NSJSONReadingOptions.AllowFragments) as! Dictionary<String, Array<Dictionary<String, String>>>
} catch (_) {
}
let array = json["NewsLetter"] as Array?
if let author = array?[0]["Author"] {
AuthorGlobal.append(author)
}
print(AuthorGlobal) // This prints - ["Tom"]
if let LastName = array?[0]["LastName"] {
print(LastName) // This prints - Holton
}
if let ArticleTitle = array?[0]["ArticleTitle"] {
//Now you got your value
print(ArticleTitle) // This prints - XcodeGhost: Apple suffers a major malware infection inside the iOS app store.
}
if let Author = array?[1]["Author"] {
//Now you got your value
print(Author) // This prints - Sam
}
if let LastName = array?[1]["LastName"] {
//Now you got your value
print(LastName) // This prints - Devaney
}
if let ArticleTitle = array?[1]["ArticleTitle"] {
//Now you got your value
print ("Article Title: " + (ArticleTitle)) // This prints - Article Title: Google is 2 Billion Lines of Code
}
}
}
I'm having trouble loading the PageViewController after the async call is complete. I was considering using NSNotification, but not sure what is the best approach.
Async func to fetch images
func fetchArrayImages() {
var query = PFQuery(className: "FoodPhoto")
query.orderByDescending("Votes")
query.findObjectsInBackgroundWithBlock ({(objects:[AnyObject]!, error: NSError!) in
if(error == nil){
let imageObjects = objects as [PFObject]
for object in objects {
let photoUploaded = object["PhotoUploaded"] as PFFile
photoUploaded.getDataInBackgroundWithBlock({
(imageData: NSData!, error: NSError!) -> Void in
if (error == nil) {
let image = UIImage(data:imageData)
//image object implementation
self.photosUploadedArray.append(image!)
}
})
}
}
else{
println("Error in retrieving \(error)")
}
})
}
Func to be called after async download images
This loads the UIPageViewController
func loadPhotosFromArray() {
var array = photosUploadedArray
view1 = PhotoCollevtionView(outerFrame: self.view.frame, photoArray: array, currentNumber: 0)
self.view.addSubview(view1!)
}
You can check your uploaded image is equals with last image in your imageObjects array and in this case you can call your loadPhotosFromArray() code like this:
self.photosUploadedArray.append(image!)
if ( imageObjects.last.isEqual(image!)) { //Use this code
loadPhotosFromArray()
}
The activity indicator starts, but does not stop when the hide function is called. I've tried putting the hide function in various places, and it still does not hide.
Hide activity indicator: Q0ViewController().hideActivityIndicator(self.view)
I'm using the swift utility function found here:
https://github.com/erangaeb/dev-notes/blob/master/swift/ViewControllerUtils.swift
Start activity indicator
override func viewDidLoad() {
super.viewDidLoad()
Q0ViewController().showActivityIndicator(self.view)
self.locationManager.delegate = self //location manager start
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
}
Hide activity indicator after query:
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
CLGeocoder().reverseGeocodeLocation(manager.location, completionHandler: { (placemarks, error) -> Void in
if (error != nil) {
println("Error:" + error.localizedDescription)
//return
}
if placemarks.count > 0 {
let pm = placemarks[0] as CLPlacemark
self.displayLocationInfo(pm)
currentLoc = manager.location
currentLocGeoPoint = PFGeoPoint(location:currentLoc)
var query = PFQuery(className:"test10000")
query.whereKey("RestaurantLoc", nearGeoPoint:currentLocGeoPoint, withinMiles:100) //filter by miles
query.limit = 1000 //limit number of results
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]!, error: NSError!) -> Void in
if objects != nil {
unfilteredRestaurantArray = objects
originalUnfilteredArray = objects
println(objects)
} else {
println("error: \(error)")
}
Q0ViewController().hideActivityIndicator(self.view) //HIDE
}
} else {
println("error: \(error)")
}
})
}
It is not an issue with the main queue as dispatch_after(DISPATCH_TIME_NOW, dispatch_get_main_queue(), { ()->() in does not resolve the issue.
Looks like you're creating a new instance of the "Q0ViewController" each time.
Instead I would suggest retaining the initial instance as a property on your class:
// As a variable on the class instance
let myViewController = Q0ViewController()
// Initially show the activity indicator
self.myViewController.showActivityIndicator(self.view)
// Hide the activity indicator
self.myViewController.hideActivityIndicator(self.view)
Hopefully this helps!
Similar to what Joshua suggested, just replaced:
Q0ViewController().showActivityIndicator(self.view)
and
Q0ViewController().hideActivityIndicator(self.view)
To:
self.showActivityIndicator(self.view)
and
self.hideActivityIndicator(self.view)
I'm combining Swift and Objective-C in the same project. I am trying to use STTwitter cocoapod like this:
// objective-c
// STTwitter category method
//
- (void)getStatusesLookupTweetIDs:(NSArray *)tweetIDs
successBlock:(void (^)(NSArray *))successBlock
errorBlock:(void (^)(NSError *))errorBlock {
[self getStatusesLookupTweetIDs:tweetIDs
includeEntities:#(YES)
trimUser:#(YES)
map:#(YES)
successBlock:successBlock
errorBlock:errorBlock];
}
Swift Code
// swift
twitterApi.getStatusesLookupTweetIDs(ids, successBlock: { (tweets: [AnyObject]!) -> Void in
process(tweets)
finish()
}, errorBlock: { (err) -> Void in
error(err)
})
Everything looks fine in Obj-C (I tried not investigate variable passed to successBlock, they all have valid values). But in Swift, when successBlock gets executed, tweets was:
Printing description of tweets:
([AnyObject]!) tweets = 1 value {
[0] = <error: use of undeclared identifier 'cocoarr'
error: 1 errors parsing expression
>
}
How do I fix this and pass NSArray into Swift? (No compile error)
That worked for me.
Instead of using:
[AnyObject]
try to use:
[Dictionary<String, AnyObject>] (or whatever class is inside the array)
Try to specify the type of the array instead AnyObject.
I hope it helps.
Cheers.
Try [[String:AnyObject]] rather than [AnyObject]
I got the same error in a smilar functionality. When changing from:
if let dictOrList = NSJSONSerialization.JSONObjectWithData(data, options:nil, error: &err) as? NSDictionary {
callbackList = [dictOrList]
} else if let list = NSJSONSerialization.JSONObjectWithData(data, options:nil, error: &err) as? [AnyObject] {
callbackList = list
}
to
if let dictOrList = NSJSONSerialization.JSONObjectWithData(data, options:nil, error: &err) as? [String: AnyObject] {
callbackList = [dictOrList]
} else if let list = NSJSONSerialization.JSONObjectWithData(data, options:nil, error: &err) as? [[String:AnyObject]] {
callbackList = list
}
I got it working.
How can I go to old scene in SpriteKit ( in Swift ) ? I am in scene1 , i paused it and i move to scene 2 and I want to get back to scene1 and i to resume it . I don't want to recreate it again .
Thanks.
EDIT :
So , I tried this :
In secondScene class i put a oldScene SKScene property and a computed setOldScene property:
class SecondScene: SKScene {
var oldScene:SKScene?
var setOldScene:SKScene? {
get { return oldScene }
set { oldScene = newValue }
}
init(size: CGSize) {
super.init(size: size)
/* Setup my scene here */
}}
And then , in FirstScene class ( where i have ONE moving ball ) , in touchBegan method i have this
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if(self.view.scene.paused) {
self.view.scene.paused = false
}
else {
self.view.scene.paused = true
}
var secondScene = SecondScene(size: self.frame.size)
secondScene.setOldScene = self.scene
if !transition { self.view.presentScene(secondScene, transition: SKTransition.doorsOpenHorizontalWithDuration(2)) ; transition = true }
}
}
But , when i call self.view.presentScene(oldScene) in SecondScene class i move yo first class and i have TWO balls that moving :-??
I can't use class variable , Xcode not suport yet .
I solved this issue by having a public property on the second scene.
And then using that to present the first scene.
So in the First Scene, when you want to show the second scene....
if let scene = SKScene(fileNamed: "SecondScene") as! SecondScene?
{
scene.parentScene = self
self.view?.presentScene(scene)
}
This following code is in the SecondScene.
When ready to return to the first scene, just call the method showPreviousScene()...
public var parentScene: SKScene? = nil
private func showPreviousScene()
{
self.view?.presentScene(parentScene!)
}
You will have to keep a reference to your old scene around, and then when you want to move back to it, simply call
skView.presentScene(firstScene)
on your SKView instance.
There are several ways to keep a reference to your class around. You could use a Singleton, or simply a class with a class type property to store the reference and access it from anywhere.