2016-02-17 13 views
6

Sto utilizzando il monitoraggio significativo della modifica della posizione. Quando eseguo il codice nel simulatore e controllo l'opzione Freeway, ricevo aggiornamenti periodici sulla posizione. Prendo questi aggiornamenti e li salvo in NSUserDefaults e aggiorno tableview ogni 10s, così posso vedere se ho degli aggiornamenti. Se eseguo l'app su un dispositivo reale, ottengo zero aggiornamenti. Ho tenuto il telefono in tasca e ho percorso più di 80 km, sono stato in 2 città. Zero aggiornamenti. Non sono sicuro se ho incasinato qualcosa. Vi allego il codice. Il codice è copia incolla, sentiti libero di testare. Assicurati di utilizzare TableViewController nello storyboard e imposta ID cella su ID. Cosa mi manca? Sono test su iPhone 5.il cambio di posizione significativo non si attiva sul dispositivo

info.plist:

enter image description here

edit: trovato questo nel docs apple. Il mio locationManager dovrebbe essere creato in modo diverso?

Quando un'applicazione viene rilanciato a causa di un aggiornamento di posizione, il lancio opzioni dizionario passato al applicazione: willFinishLaunchingWithOptions: o applicazione: didFinishLaunchingWithOptions: metodo contiene la chiave UIApplicationLaunchOptionsLocationKey. La presenza di quel tasto segnala che i nuovi dati sulla posizione sono in attesa di essere consegnati alla tua app. Per ottenere tali dati, è necessario creare un nuovo oggetto CLLocationManager e riavviare i servizi di localizzazione che erano in esecuzione prima della terminazione dell'app . Quando si riavviano tali servizi, il responsabile della posizione consegna tutti gli aggiornamenti di posizione in sospeso al delegato.

EDIT2:

Sulla base di questo, la posizione deve essere aggiornato almeno ogni 15 minuti. Bug nel mio codice confermato.

Se la precisione a livello di GPS non è fondamentale per la vostra applicazione e non è necessario continuo monitoraggio, è possibile utilizzare il significativo cambiamento di servizio di localizzazione . È fondamentale utilizzare il servizio di cambio di posizione significativo in modo corretto, poiché riattiva il sistema e l'app almeno ogni 15 minuti, anche se non si sono verificati cambiamenti di posizione e il suo viene eseguito continuamente fino a quando non viene interrotto.

edit3: aggiunto questo codice a AppDelegate didFinishLaunchingWithOptions: per vedere se l'app si risveglia. Non si risveglia, non vedo la voce 200 200 nella vista tabella. Sta succedendo qualcosa di strano.

if let options = launchOptions { 
      print("options") 
      if (launchOptions![UIApplicationLaunchOptionsLocationKey] != nil){ 
       locationManager.startUpdatingLocation() 
       self.lat.append(Double(200)) 
       self.lon.append(Double(200)) 
       self.times.append(NSDateFormatter.localizedStringFromDate(NSDate(), dateStyle: .NoStyle, timeStyle: .ShortStyle)) 
       NSUserDefaults.standardUserDefaults().setObject(lat, forKey: "lat") 
       NSUserDefaults.standardUserDefaults().setObject(lon, forKey: "lon") 
       NSUserDefaults.standardUserDefaults().setObject(times, forKey: "time") 
      } 

CODICE: // AppDelegate:

import UIKit 
import CoreLocation 

@UIApplicationMain 
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate { 

    var lat:[CLLocationDegrees]! 
    var lon:[CLLocationDegrees]! 
    var times:[String]! 
    var distances: [String]! 

    var window: UIWindow? 
    var locationManager: CLLocationManager! 


    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 

     locationManager=CLLocationManager() 
     locationManager.delegate=self 
     locationManager.requestAlwaysAuthorization() 

     let isFirstLaunch = NSUserDefaults.standardUserDefaults().objectForKey("lat") 
     if isFirstLaunch == nil{ 
      lat = [CLLocationDegrees]() 
      lon = [CLLocationDegrees]() 
      times = [String]() 
      NSUserDefaults.standardUserDefaults().setObject(lat, forKey: "lat") 
      NSUserDefaults.standardUserDefaults().setObject(lon, forKey: "lon") 
      NSUserDefaults.standardUserDefaults().setObject(times, forKey: "time") 
     }else{ 
      lat = NSUserDefaults.standardUserDefaults().arrayForKey("lat") as! [CLLocationDegrees] 
      lon = NSUserDefaults.standardUserDefaults().arrayForKey("lon") as! [CLLocationDegrees] 
      times = NSUserDefaults.standardUserDefaults().objectForKey("time") as! [String] 
//   distances = NSUserDefaults.standardUserDefaults().objectForKey("distance") as! [String] 

     } 
     return true 
    } 



    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { 
     print("location updated") 

     self.lat.append(locations[0].coordinate.latitude) 
     self.lon.append(locations[0].coordinate.longitude) 
     self.times.append(NSDateFormatter.localizedStringFromDate(NSDate(), dateStyle: .NoStyle, timeStyle: .ShortStyle)) 

     NSUserDefaults.standardUserDefaults().setObject(lat, forKey: "lat") 
     NSUserDefaults.standardUserDefaults().setObject(lon, forKey: "lon") 
     NSUserDefaults.standardUserDefaults().setObject(times, forKey: "time") 

     print("Location: \(locations[0].coordinate.latitude) \(locations[0].coordinate.longitude)") 
    } 

    func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) { 
     print("did change AS") 
     switch status { 
     case .AuthorizedWhenInUse: 
      locationManager.startMonitoringSignificantLocationChanges() 
     case .AuthorizedAlways: 
      print("to always") 
      locationManager.startMonitoringSignificantLocationChanges() 
      if lat.count==0{ 
       self.lat.append((locationManager.location?.coordinate.latitude)!) 
       self.lon.append((locationManager.location?.coordinate.longitude)!) 

       self.times.append(NSDateFormatter.localizedStringFromDate(NSDate(), dateStyle: .NoStyle, timeStyle: .ShortStyle)) 

       NSUserDefaults.standardUserDefaults().setObject(lat, forKey: "lat") 
       NSUserDefaults.standardUserDefaults().setObject(lon, forKey: "lon") 
       NSUserDefaults.standardUserDefaults().setObject(times, forKey: "time") 


      } 

//   locationManager.startUpdatingLocation() 
      break 
     default: 
      locationManager.stopMonitoringSignificantLocationChanges() 
      break 
     } 
    } 
} 

// View Controller

import UIKit 

class TableViewController: UITableViewController { 

    let appDel = UIApplication.sharedApplication().delegate as! AppDelegate 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     NSTimer.scheduledTimerWithTimeInterval(10, target: self, selector: "updateTableView", userInfo: nil, repeats: true) 
    } 



    override func numberOfSectionsInTableView(tableView: UITableView) -> Int { 
     // #warning Incomplete implementation, return the number of sections 
     return 1 
    } 

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     // #warning Incomplete implementation, return the number of rows 
     return appDel.lon.count 
    } 


    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
     let cell = tableView.dequeueReusableCellWithIdentifier("ID", forIndexPath: indexPath) 
     cell.textLabel?.text = "\(appDel.lat[indexPath.row]) \(appDel.lon[indexPath.row]) \(appDel.times[indexPath.row])" 
     cell.textLabel?.font = UIFont.systemFontOfSize(9) 


     return cell 
    } 

    func updateTableView(){ 
    self.tableView.reloadData() 
    } 
} 
+0

Vede effettivamente la richiesta di autorizzazione? In caso contrario, hai NSLocationAlwaysUsageDescription nel tuo plist? –

+0

sì la richiesta si apre.E sì, la stringa NSLocationAlwaysUsageDescription è impostata in info.plist. – brumbrum

+0

Stai uccidendo l'app toccando due volte il pulsante Home e scorrendo verso l'alto sull'app? Se uccidi un'applicazione in questo modo, non eseguirà servizi di modifica significativi in ​​background. – Rob

risposta

14

Ci sono diversi problemi con il codice:

  1. La posizione aggiornamenti non vengono avviati quando l'applicazione viene avviata da iOS.
  2. Gli aggiornamenti della posizione in background non sono richiesti.
  3. Il codice si basa su cambiamenti nello stato di autorizzazione ad avviare gli aggiornamenti di posizione
  4. C'è un'istruzione break mancante nel metodo di didChangeAuthorizationStatus.

Qui ci sono i documenti pertinenti:

Il primo documento dice un oggetto location manager deve essere completamente configurato quando iOS lancia l'applicazione quindi l'evento location può essere consegnato all'app.

Al riavvio, è necessario configurare ancora un oggetto gestore località e chiamare questo metodo [startMonitoringSignificantLocationChanges] per continuare a ricevere gli eventi posizione.

Ecco come faccio in genere per garantire che il gestore di posizione sia completamente avviato indipendentemente dal fatto che sia stato lanciato dall'icona o da iOS (scusate, io uso ObjectiveC).

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 
// Override point for customization after application launch. 

    NSLog(@"app launching"); 
    bgTask = UIBackgroundTaskInvalid; 

    locationMgr = [[CLLocationManager alloc] init]; 
    [locationMgr setDelegate:self]; 
    if([locationMgr respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) 
    [locationMgr setAllowsBackgroundLocationUpdates:YES]; 
    CLAuthorizationStatus authorizationStatus= [CLLocationManager authorizationStatus]; 

    if([launchOptions valueForKey:UIApplicationLaunchOptionsLocationKey] != nil) { 
    NSLog(@"relaunching because of significant location change - restarting SLC"); 
    [locationMgr startMonitoringSignificantLocationChanges]; 
    } 
    else 
    { 
    if (authorizationStatus == kCLAuthorizationStatusAuthorizedAlways) { 
     NSLog(@"launching with authorization to always use location - starting SLC"); 
     [locationMgr startMonitoringSignificantLocationChanges]; 
    } 
    else 
    { 
     NSLog(@"launching with no authorization to always use location - requesting authorization"); 
     if([locationMgr respondsToSelector:@selector(requestAlwaysAuthorization)]) 
      [locationMgr requestAlwaysAuthorization]; 
    } 
    } 

    return YES; 
} 

Avviso la chiamata a setAllowsBackgroundLocationUpdates. Questo è nuovo in iOS9 e deve essere eseguito ogni volta che l'app viene avviata se si desidera ricevere aggiornamenti delle posizioni in background. (È come un "Non sto scherzando, so che li ho richiesti in modalità background, ma li voglio davvero").

Le applicazioni che desiderano ricevere gli aggiornamenti di posizione quando sospesa deve includere la chiave UIBackgroundModes (con il valore posizione) nel file Info.plist di loro app e impostare il valore di questa proprietà su Sì.

Infine, non si può contare su didChangeAuthorizationStatus chiamato. Se avete l'autorizzazione kCLAuthorizationStatusAuthorizedAlways quindi chiamando [locationMgr requestAlwaysAuthorization] non si traduca in un cambiamento di stato di autorizzazione, in modo da didChangeAuthorizationStatus non viene chiamato.

Se lo stato di autorizzazione è già noto quando si chiama il metodo requestWhenInUseAuthorization o requestAlwaysAuthorization, il responsabile posizione non segnala lo stato corrente dell'autorizzazione a questo metodo.

+0

Signore, meriti milioni di voti. Grazie! – brumbrum

+0

Nessun problema: Apple ha reso costantemente più difficile l'utilizzo corretto di CoreLocation in tutte le versioni di iOS. Penso che fosse perfetto per iOS6, ora è semplicemente arcano. Buona fortuna con il vostro progetto. – BitByteDog

+1

Non posso discutere con quello. In una nota a margine. Ho giocato in giro per un paio di giorni. Apple annuncia che la posizione significativa verrà attivata almeno ogni 15 minuti, indipendentemente dal cambio effettivo della posizione. Non ricevo aggiornamenti se non mi sto muovendo. Vedi aggiornamenti di posizione nelle tue app ogni 15 minuti, anche se non ti stai spostando? – brumbrum

0

io penso che si debba startUpdatingLocation a prescindere? Hai provato a inserire punti di interruzione per vedere dove sei arrivato?

+0

se ho impostato startUpdatingLocation su true, ricevo 3 aggiornamenti al secondo. Penso che sia solo meschino per i servizi di localizzazione standard. Non ho, perché funziona benissimo su un simulatore. – brumbrum

+0

È possibile utilizzare i punti di interruzione su un'app sospesa in background? – brumbrum

+0

@ krompir2 - No, in questo caso non è possibile utilizzare i punti di interruzione. Generalmente i messaggi di 'NSLog' (quindi posso guardare la console). Ho anche trovato utile registrare i messaggi in una memoria persistente e poi quando porto l'app in primo piano, mostra questi messaggi salvati in una vista tabella o qualcosa del genere, così posso diagnosticare ciò che è accaduto mentre l'app non era in primo piano. – Rob

Problemi correlati