使用 Alamofire 在 tableview 中操作 YouTube 播放列表 API

Posted

技术标签:

【中文标题】使用 Alamofire 在 tableview 中操作 YouTube 播放列表 API【英文标题】:Manipulate YouTube Playlist API in tableview using Alamofire 【发布时间】:2017-01-30 18:43:33 【问题描述】:

我四处寻找我的问题的答案,但我没有运气。我是编码新手,尤其是 Swift 3.0。

我正在尝试在我的项目中使用 Alamofire 可可豆荚在表格视图中动态解析 YouTube 播放列表。我的项目包含:一个名为“videosViewController”的视图控制器,它包含 tableview,一个名为“Video”的类,它包含我从 youtube API 解析的项目,另一个名为“VideoModel”的类包含削减这些项目的方法。当我运行我的项目时,控制台成功解析了项目,但随后项目在代码行崩溃:

for video in (data["items"] as? NSDictionary)! 

带有“无法将 '__NSArrayI' (0x10d2ebd88) 类型的值转换为 'NSDictionary' (0x10d2ec288)。”错误如下图

Project crash

Console details

这里是我使用的代码的 sn-p:

videosViewController:

 import UIKit

 class videosViewController: UIViewController, UITableViewDelegate,      UITableViewDataSource 

@IBOutlet var tableView: UITableView!

var videos:[Video] = [Video]()
var selectedVideo: Video?


override func viewDidLoad() 
    super.viewDidLoad()

    // Do any additional setup after loading the view.

    let model = VideoModel()

     model.fetchVideos()

    self.tableView.dataSource = self
    self.tableView.delegate = self


override func didReceiveMemoryWarning() 
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.


func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
    return (self.view.frame.size.width / 320)  * 180


func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    return videos.count


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let cell = tableView.dequeueReusableCell(withIdentifier: "BasicCell")!

    let videoTitle = videos[indexPath.row].videoTitle
    let label = cell.viewWithTag(2) as! UILabel
    label.text = videoTitle

    let videoThumbnailUrlString = "https://i1.ytimg.com/vi/" + videos[indexPath.row].videoId + "/maxresdefault.jpg"

    let videoThumbnailUrl = NSURL(string: videoThumbnailUrlString)

    if videoThumbnailUrl != nil 

        let request = URLRequest(url: videoThumbnailUrl! as URL)

        let session = URLSession.shared

        let task = session.dataTask(with: request,
                                    completionHandler:  (data:Data?,
                                        response:URLResponse?,
                                        error:Error?) -> Void in

                                        DispatchQueue.main.async 

                                        let imageView = cell.viewWithTag(1) as! UIImageView


                                        imageView.image = UIImage(data: data!)

                                        


        )



    task.resume()
    

    return cell


func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
    self.selectedVideo = self.videos[indexPath.row]

    self.performSegue(withIdentifier: "goToDetail", sender: self)


override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
    let detailView = segue.destination as! videoDetailViewController

    detailView.selectedVideo = self.selectedVideo





视频类:

import UIKit

class Video: NSObject 

var videoId:String = ""
var videoTitle:String = ""
var videoDescription:String = ""
var videoThumbnailURL = ""


还有 VideoModel 类:

import UIKit
import Alamofire

class VideoModel: NSObject 

let parameters: Parameters = ["part":"snippet","playlistId":"PLMRqhzcHGw1ZRUB86rmNqG15Sr5jV-2NU","key":"AIzaSyDdNXhz3H7ifXB-qfOVakz0Xps2Y-kP0R0"]

var videoArray = [Video]()

func fetchVideos() 


    Alamofire.request("https://www.googleapis.com/youtube/v3/playlistItems", method: .get, parameters: parameters, encoding: URLEncoding.default, headers: nil).responseJSON  (response:DataResponse<Any>) in


        switch(response.result) 
        case .success(let JSON):
            print("Success with JSON: \(JSON)")



            if let data = response.result.value as? [String: AnyObject] 
                // print(response.result.value)

                var arrayOfVideos = [Video]()

                for video in (data["items"] as? NSDictionary)! 

                    let videoObj = Video()


                    videoObj.videoId = (video.value as? NSDictionary)?["snippet.resourceId.videoId"] as? String ?? ""
                    videoObj.videoTitle = (video.value as? NSDictionary)?["snippet.title"] as? String ?? ""
                    videoObj.videoDescription = (video.value as? NSDictionary)?["snippet.description"] as? String ?? ""
                    videoObj.videoThumbnailURL = (video.value as? NSDictionary)?["snippet.thumbnails.maxres.url"] as? String ?? ""

                    print(video)

                    // You need to parse the items into the video data
                    arrayOfVideos.append(videoObj)
                



                self.videoArray = arrayOfVideos

                // 



            

        case .failure(let error):
            print("Request failed with error: \(error)")
        
    


【问题讨论】:

错误告诉您data["items"] 是一个数组,但您将其作为字典抓取。我不确切知道返回的数据是什么样的,但我猜它的items 键可能包含一个字典数组。 (data["items"] as? NSArray) 可能会起作用。 感谢您的帮助,但是当我遵循您的建议时,我收到了一些错误,如下所示:'NSFastEnumerationIterator.Element' 类型的值(又名'Any')没有成员'值''跨度> 如何重写这个数组中的项目? 您期望video 是什么?你可能需要告诉它会发生什么。我会尝试使用guard let videoAsType = video as? &lt;ExpectedClassOfVideo&gt; else // handle error case(或类似的if let),然后从videoAsType而不是video读取video.value 【参考方案1】:

替换

as? NSDictionary

as? [String:Any]

for video in (data["items"] as? NSDictionary)!

Bcs:您必须将类型 Any 转换为 Swift 字典类型 [String:Any]。

if let JSON = response.result.value  as?  [String : Any] 
   if let items =  JSON["items"] as? [[String : Any]] 
        for video in items 
              //Other code
        
   

【讨论】:

以上是关于使用 Alamofire 在 tableview 中操作 YouTube 播放列表 API的主要内容,如果未能解决你的问题,请参考以下文章

使用 Alamofire 在 tableview 中操作 YouTube 播放列表 API

通过 Alamofire,想获取数据并将其插入 TableView,但在完成插入之前,TableView 已加载

Swift 3 / Alamofire 4:在 TableView 上使用 ID 获取数据

在使用两个嵌套的 alamofire 请求滚动之前,TableView 不显示数据

如何使用来自 Alamofire 的 JSON 数据填充 tableview?

如何使用 Alamofire 请求在我的 tableView 中显示我的数据