2017-09-28 3 views
1

Ich habe eine Split-View-Controller mit der Top-View-Controller auf einen Tabellenansicht-Controller, der eine Liste von Wiedergabelisten zur Auswahl angezeigt wird. Wenn die App zum ersten Mal geladen wird, fragt sie nach Musikzugriffsberechtigungen. Beantworten Sie die Frage mit Ja, aber die Tabellendarstellung zeigt keine Wiedergabelisten an. Am Ende muss ich die App beenden und sie erneut ausführen. Frage ich nach Musikbibliothek Erlaubnis den falschen Ort? Es ist in der ViewWillAppear des Topview-Controllers und speichert die Playlists, die ich verwende (da einige aussortiert sind), in einer Klasse von Playlists.Swift fragen Musik Erlaubnis für die erste Ansicht Controller

 override func viewWillAppear(_ animated: Bool) { 
    self.clearsSelectionOnViewWillAppear = self.splitViewController!.isCollapsed 
    super.viewWillAppear(animated) 

    checkMediaAccessAndSetup() 
} 

func checkMediaAccessAndSetup() { 
    let authorizationStatus = MPMediaLibrary.authorizationStatus() 
    switch authorizationStatus { 
    case .notDetermined: 
     // Show the permission prompt. 
     MPMediaLibrary.requestAuthorization({[weak self] (newAuthorizationStatus: MPMediaLibraryAuthorizationStatus) in 
      // Try again after the prompt is dismissed. 
      self?.checkMediaAccessAndSetup() 
     }) 
    case .denied, .restricted: 
     // Do not use MPMediaQuery. 
     return 
    default: 
     // Proceed as usual. 
     break 
    } 
    // Do stuff with MPMediaQuery 
    self.setupPlaylistStore() 
    tableView.reloadData() 
} 
+0

Da der RequestAuthorization Block der MPMediaLibrary als [weak self] implementiert ist, kann self innerhalb des Blocks nil sein. Sind Sie sicher, dass die checkMediaAccessAndSetup-Methode aufgerufen wird, nachdem Sie eine Autorisierung für MPMediaLibrary angefordert haben? – Rendel

+0

Es kann sein, dass der Aufruf von 'requestAuthorization' nicht im Hauptthread aufgerufen wird. Versuchen Sie 'self? .checkMediaAccessAndSetup()' innerhalb 'DispatchQueue.main.async {}' –

+0

Versuchtes self.checkMediaAccessAndSetup() innerhalb von DispatchQueue.main.async {} in viewWillAppear (es wird nicht erlauben, selbst? .checkMediaAccessAndSetup()) . Gleiche Sache. – EdZ

Antwort

0

Die Hauptprobleme mit Ihrem Code sind

  • Sie vollständig mit der Tatsache zu kämpfen scheitern, dass die requestAuthorization Vervollständigungsfunktion auf einem Hintergrund-Thread aufgerufen wird. Sie müssen zum Hauptthread wechseln, um an der Schnittstelle zu arbeiten.

  • Sie haben den wichtigen Fall .authorized weggelassen. Wenn Sie Arbeit zu tun haben hängt davon ab, Ihren Autorisierungsstatus, müssen Sie es jetzt tun, wenn Sie berechtigt sind, aber nach der Autorisierung, wenn Sie nicht bestimmt sind.

Somit ist dies das richtige System für eine kohärente Berechtigungsprüfung (wo f() ist das, was Sie immer tun, wenn Sie können):

let status = MPMediaLibrary.authorizationStatus() 
switch status { 
case .authorized: 
    f() 
case .notDetermined: 
    MPMediaLibrary.requestAuthorization() { status in 
     if status == .authorized { 
      DispatchQueue.main.async { 
       f() 
      } 
     } 
    } 
// ... 
} 

Wenn Sie abstrakte dieser Code in ein Dienstprogramm Methode, wo f kann alles sein, können Sie dies überall in Ihrer App, wo eine Autorisierung erforderlich sein könnte - nicht nur beim Start.

+0

Perfekt! Danke, ja, ich habe es nicht verstanden, aber jetzt. – EdZ

-1

Danke für die Kommentare, es gab mir Hinweise des Multi-Threading, das vorging und ich konnte es mit einem Timer Anruf beheben, wenn es keine Wiedergabelisten in der Klasse waren bei der Kontrolle zu halten und neu zu laden die Tabellendaten.

override func viewWillAppear(_ animated: Bool) { 
    self.clearsSelectionOnViewWillAppear = self.splitViewController!.isCollapsed 
    super.viewWillAppear(animated) 

    checkMediaAccess() 
    self.setupPlaylistStore() 
    tableView.reloadData() 
    if store.allPlaylists.count < 1 { 
     playlistTimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector:  #selector(self.playlistTimerCall), userInfo: nil, repeats: true) 
    } 
} 

@objc func playlistTimerCall() { 
    self.setupPlaylistStore() 
    if store.allPlaylists.count > 1 { 
     tableView.reloadData() 
     playlistTimer?.invalidate() 
    } 
} 
func checkMediaAccess() { 
    let authorizationStatus = MPMediaLibrary.authorizationStatus() 
    switch authorizationStatus { 
    case .notDetermined: 
     // Show the permission prompt. 
     MPMediaLibrary.requestAuthorization({[weak self] (newAuthorizationStatus: MPMediaLibraryAuthorizationStatus) in 
      // Try again after the prompt is dismissed. 
      self?.checkMediaAccess() 
     }) 
    case .denied, .restricted: 
     // Do not use MPMediaQuery. 
     return 
    default: 
     // Proceed as usual. 
     break 
    } 
} 


func setupPlaylistStore() { 

    // purge store 
    store.clearAllPlaylists() 

    // create a query of media items in playlist 
    let myPlayListsQuery = MPMediaQuery.playlists() 
    if myPlayListsQuery.collections != nil { 
     playlists = myPlayListsQuery.collections! 
    } 

    // add playlists to MyPlaylist(s) 
    if playlists.count > 0 { 
     for index in 0...playlists.count - 1 { 
      let playlist = playlists[index] 
      store.addPlaylist(playlist: playlist as! MPMediaPlaylist) 
     } 
    } 
    var toBeRemoved = [Int]() 
    let defaults = UserDefaults.standard 
    if defaults.bool(forKey: "exclude_smart_playlists") { 
     //smart 
     for index in 0...(playlists.count - 1) { 
      let playlist = playlists[index] 
      let theAttributes = playlist.value(forProperty: MPMediaPlaylistPropertyPlaylistAttributes) as! Int 
      if theAttributes == 2 { 
       toBeRemoved.append(index) 
      } 
     } 
    } 
    if defaults.bool(forKey: "exclude_folders") { 
     //folders 
     for index in 0...(playlists.count - 1) { 
      let playlist = playlists[index] 
      let isFolder = playlist.value(forProperty: "isFolder") 
      let stringIsFolder = String("\(String(describing: isFolder))") 
      if ((stringIsFolder.range(of: "1")) != nil) { 
       toBeRemoved.append(index) 
      } 
     } 
    } 
    //sort from the last to the first so i don't reindex 
    let reverseSortedPlaylists = toBeRemoved.sorted(by: >) 

    // remove the unwanted playlists 
    for list in reverseSortedPlaylists { 
     store.removePlaylist(index: list) 
    } 
} 
+0

Dem kann ich nicht zustimmen. Mit einem Timer ist dieser Weg einfach skanky. Ich habe eine App, die Playlists anzeigt und solche Hacks nicht benötigt. Es ist nur eine Frage der Dinge in der richtigen Reihenfolge zu tun. Vielleicht liegt das Problem in Ihrem 'setupPlaylistStore', den Sie nicht angezeigt haben. – matt

+0

Der setupPlaylistStore wurde hinzugefügt. Ich stimme dem zu, konnte aber sehen, dass alles angerufen wurde, bevor eine Genehmigung erteilt wurde. Offen für andere Vorschläge, aber das Setup hat immer noch gesagt, nicht autorisiert (noch). – EdZ

+0

"alles wurde aufgerufen, bevor eine Genehmigung erteilt wurde" Sicher, aber Ihre Aufgabe ist es, diese Möglichkeit kohärent zu bewältigen und alles erneut zu rufen, wenn die Berechtigung erteilt wird - als Antwort auf die Autorisierung (nicht in einem _Timer_, der gerade Vermutungen, wann dies passiert sein könnte). – matt

Verwandte Themen