我正在尝试从 SKCloudServiceController 运行以下功能,但出于某种原因,每次运行时,应用程序都会卡住。我已经测试了我的开发人员 token ,它确实有效。我正在运行 Xcode 12.2。也许有一个更新会使它不再工作?
我已经测试了 token 并且它有效。
class AppleMusicAPI {
let developerToken = "b'eyJ0{...}RDlRSlFw'"
func getUserToken() -> String {
var userToken = String()
let lock = DispatchSemaphore(value: 0)
func requestAccess(_ completion: @escaping(String?) -> Void) {
SKCloudServiceController().requestUserToken(forDeveloperToken: developerToken) { (receivedToken, error) in
completion(receivedToken)
}
}
requestAccess( { (completeToken) in
if let token = completeToken {
userToken = token
lock.signal()
}
})
lock.wait()
return userToken
}
func fetchStorefrontID() -> String {
let lock = DispatchSemaphore(value: 0)
var storefrontID: String!
let musicURL = URL(string: "https://api.music.apple.com/v1/me/storefront")!
var musicRequest = URLRequest(url: musicURL)
musicRequest.httpMethod = "GET"
musicRequest.addValue("Bearer \(developerToken)", forHTTPHeaderField: "Authorization")
musicRequest.addValue(getUserToken(), forHTTPHeaderField: "Music-User-Token")
URLSession.shared.dataTask(with: musicRequest) { (data, response, error) in
guard error == nil else { return }
if let json = try? JSON(data: data!) {
let result = (json["data"]).array!
let id = (result[0].dictionaryValue)["id"]!
storefrontID = id.stringValue
lock.signal()
}
}.resume()
lock.wait()
return storefrontID
}
func searchAppleMusic(_ searchTerm: String!) -> [Song] {
let lock = DispatchSemaphore(value: 0)
var songs = [Song]()
let musicURL = URL(string: "https://api.music.apple.com/v1/catalog/\(fetchStorefrontID())/search?term=\(searchTerm.replacingOccurrences(of: " ", with: "+"))&types=songs&limit=25")!
var musicRequest = URLRequest(url: musicURL)
musicRequest.httpMethod = "GET"
musicRequest.addValue("Bearer \(developerToken)", forHTTPHeaderField: "Authorization")
musicRequest.addValue(getUserToken(), forHTTPHeaderField: "Music-User-Token")
URLSession.shared.dataTask(with: musicRequest) { (data, response, error) in
guard error == nil else { return }
if let json = try? JSON(data: data!) {
let result = (json["results"]["songs"]["data"]).array!
for song in result {
let attributes = song["attributes"]
let currentSong = Song(id: attributes["playParams"]["id"].string!, name: attributes["name"].string!, artistName: attributes["artistName"].string!, artworkURL: attributes["artwork"]["url"].string!)
songs.append(currentSong)
}
lock.signal()
} else {
lock.signal()
}
}.resume()
lock.wait()
return songs
}
}
最佳答案
我对发生的事情有一个理论:由于在主线程上调用了 requestUserToken 函数,因此使用信号量会造成无限等待(在同一线程上调用 lock.wait() 和 lock.signal())。最终对我有用的是使用完成处理程序而不是信号量。所以我的 getUserToken 函数看起来像这样:
func getUserToken(completion: @escaping(_ userToken: String) -> Void) -> String {
SKCloudServiceController().requestUserToken(forDeveloperToken: developerToken) { (userToken, error) in
guard error == nil else {
return
}
completion(userToken)
}
}
在任何需要 userToken 的后续函数中,我将其作为参数传入:
func fetchStorefrontID(userToken: String, completion: @escaping(String) -> Void){
var storefrontID: String!
let musicURL = URL(string: "https://api.music.apple.com/v1/me/storefront")!
var musicRequest = URLRequest(url: musicURL)
musicRequest.httpMethod = "GET"
musicRequest.addValue("Bearer \(developerToken)", forHTTPHeaderField: "Authorization")
musicRequest.addValue(userToken, forHTTPHeaderField: "Music-User-Token")
URLSession.shared.dataTask(with: musicRequest) { (data, response, error) in
guard error == nil else { return }
if let json = try? JSON(data: data!) {
let result = (json["data"]).array!
let id = (result[0].dictionaryValue)["id"]!
storefrontID = id.stringValue
completion(storefrontID)
}
}.resume()
}
通过首先调用 getUserToken 然后在其完成处理程序中调用 fetchStorefrontID 来调用 fetchStorefrontID
getUserToken{ userToken in
fetchStorefrontID(userToken){ storefrontID in
print(storefrontID)
//anything you want to do with storefrontID here
}
}
这就是最终对我有用的东西。
关于ios - SKCloudServiceController().requestUserToken 在 iOS 14.2 上卡住,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65057320/