Hide Activity Indicator Does Not Work - objective-c

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)

Related

Swift Here API Examples

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.

Appending JsonFile (UrL) in array to display on application

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
}
}
}

Using XCTest, how can one chain together multiple discrete sequences of { expectations -> wait }?

The documentation for XCTest waitForExpectationsWithTimeout:handler:, states that
Only one -waitForExpectationsWithTimeout:handler: can be active at any given time, but multiple discrete sequences of { expectations -> wait } can be chained together.
However, I have no idea how to implement this, nor can I find any examples. I'm working on a class that first needs to find all available serial ports, pick the correct port and then connect to the device attached to that port. So, I'm working with at least two expectations, XCTestExpectation *expectationAllAvailablePorts and *expectationConnectedToDevice. How would I chain those two?
I do the following and it works.
expectation = [self expectationWithDescription:#"Testing Async Method Works!"];
[AsynClass method:parameter callbackFunction:^(BOOL callbackStatus, NSMutableArray* array) {
[expectation fulfil];
// whatever
}];
[self waitForExpectationsWithTimeout:5 handler:^(NSError *error) {
if (error) {
XCTFail(#"Expectation Failed with error: %#", error);
}
NSLog(#"expectation wait until handler finished ");
}];
// do it again
expectation = [self expectationWithDescription:#"Testing Async Method Works!"];
[CallBackClass method:parameter callbackFunction:^(BOOL callbackStatus, NSMutableArray* array) {
[expectation fulfil];
// whatever
}];
[self waitForExpectationsWithTimeout:5 handler:^(NSError *error) {
if (error) {
XCTFail(#"Expectation Failed with error: %#", error);
}
NSLog(#"expectation wait until handler finished ");
}];
swift
let expectation1 = //your definition
let expectation2 = //your definition
let result = XCTWaiter().wait(for: [expectation1, expectation2], timeout: 10, enforceOrder: true)
if result == .completed {
//all expectations completed in order
}
Assigning my expectation to a weak variable worked for me.
This seems to be working for me in Swift 3.0 as well.
let spyDelegate = SpyDelegate()
var asyncExpectation = expectation(description: "firstExpectation")
spyDelegate.asyncExpectation = asyncExpectation
let testee = MyClassToTest(delegate: spyDelegate)
testee.myFunction() //asyncExpectation.fulfill() happens here, implemented in SpyDelegate
waitForExpectations(timeout: 30.0) { (error: Error?) in
if let error = error {
XCTFail("error: \(error)")
}
}
asyncExpectation = expectation(description: "secoundExpectation")
spyDelegate.asyncExpectation = asyncExpectation
testee.delegate = spyDelegate
testee.myOtherFunction() //asyncExpectation.fulfill() happens here, implemented in SpyDelegate
waitForExpectations(timeout: 30.0) { (error: Error?) in
if let error = error {
XCTFail("error: \(error)")
}
}
Within a class that extends XCTestCase you can use wait(for:timeout:) like this:
let expectation1 = self.expectation(description: "expectation 1")
let expectation2 = self.expectation(description: "expectation 2")
let expectation3 = self.expectation(description: "expectation 3")
let expectation4 = self.expectation(description: "expectation 4")
// ...
// Do some asyc stuff, call expectation.fulfill() on each of the above expectations.
// ...
wait(for:[expectation1,expectation2,expectation3,expectation4], timeout: 8)

Load PageViewController After Asynchronous Task Complete

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()
}

Return Value from Function Swift

I know this is probably a simple queston, I would like to return the value of currentLocGeoPoint and return the array of Objects which is of type PFObject.
Tried to save it as a global variable, but it doesn't work because it is asynchronous and doesn't take a value yet. Returns empty.
Tried to return currentLocGeoPoint and changed Void in to PFGeoPoint in. Gives error: PFGeoPoint is not convertible to 'Void'
So I'm not sure how I can fetch the variable currentLocGeoPoint.
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:"Bar")
query.whereKey("BarLocation", nearGeoPoint:currentLocGeoPoint, withinMiles:10)
query.limit = 500
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]!, error: NSError!) -> Void in
if objects != nil {
} else {
println("error: \(error)")
}
}
} else {
println("error: \(error)")
}
})
}
I don't understand the notion of "I want to return currentLocGeoPoint". Return it to what? You're in a CLLocationManagerDelegate method, so there's no one to return it to.
What you could do, though, is, when the request is done (i.e. within this closure), call some other function that needed the currentLocGeoPoint. Or you could update the UI to reflect the updated information (make sure to dispatch that update to the main thread, though). Or, if you have other view controllers or model objects that need to know about the new data, you might post a notification, letting them know that there is an updated currentLocGeoPoint. But within this method, there's no one to whom you would "return" the data.
You could assign it to a stored property of your class. Just use
self.<property> = currentLocGeoPoint