相同的方法适用于ViewDidLoad,但不适用于自定义TableViewCell按钮操作

时间:2015-05-08 23:51:30

标签: ios swift core-data

我正在学习iOS swift并创建一个应用程序,以便在使用Itunes搜索API时学习获取JSON数据并将此数据保存到CoreData。我有一个表视图,并使用自定义表视图单元格,它有一些标签,图像和下载按钮。我的目的是能够在单击单元格按钮后将专辑和该专辑信息中的所有歌曲输入CoreData。以下列出了有效和无效的内容:

  1. 点击该按钮可为我提供相册的正确CollectionId。
  2. 相册信息已成功添加到CoreData。
  3. 我在下载操作方法中调用api后无法填充我的歌曲数组。它保持空白。请注意,当我使用手动输入的集合ID调用ViewDidLoad中的api时,将填充songs数组。
  4. 代码: API控制器获取歌曲信息。

    import Foundation
    
    protocol songAPIControllerForCoreDataProtocol {
        func didReceiveAPISongResults(results: NSDictionary)
    }
    
    class songAPIControllerForCoreData {
    
        var delegate: songAPIControllerForCoreDataProtocol
    
        init(delegate: songAPIControllerForCoreDataProtocol) {
            self.delegate = delegate
        }
    
        func searchItunesForSongsBelongingTo(searchTerm: String) {
    
        // The iTunes API wants multiple terms separated by + symbols, so I'm replacing spaces with + signs
            let itunesSearchTerm = searchTerm.stringByReplacingOccurrencesOfString(" ", withString: "+", options: NSStringCompareOptions.CaseInsensitiveSearch, range: nil)
    
        // Escape anything else that isn't URL-friendly
            if let escapedSearchTerm = itunesSearchTerm.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) {
            // Using Itunes search api to find people that has a music album with the entered search term
                let urlPath = "https://itunes.apple.com/lookup?id=\(escapedSearchTerm)&entity=song"
                let url: NSURL = NSURL(string: urlPath)!
                let session = NSURLSession.sharedSession()
                let task = session.dataTaskWithURL(url, completionHandler: {data, response, error -> Void in
                println("Task completed")
                    if(error != nil) {
                    // If there is an error in the web request, print it to the console
                        println(error.localizedDescription)
                    }
                    var err: NSError?
    
                    var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as! NSDictionary
                    println(jsonResult[0])
                    if(err != nil) {
                    // If there is an error parsing JSON, print it to the console
                        println("JSON Error \(err!.localizedDescription)")
                    }
                    self.delegate.didReceiveAPISongResults(jsonResult)
                    println(jsonResult)
                })
    
                task.resume()
            }
        }
    }
    

    Song class(非CoreData):

    import Foundation
    
    class Song {
        var title: String
        var previewURL: String
        var collectionID: Int
    
        init(title: String, previewURL: String, collectionID: Int) {
            self.title = title
            self.previewURL = previewURL
            self.collectionID = collectionID
        }
    
        class func songsWithJSON(allResults: NSArray) -> [Song] {
    
            // Create an empty array of Albums to append to from this list
            var songs = [Song]()
    
            // Store the results in our table data array
            if allResults.count>0 {
    
                // Sometimes iTunes returns a collection, not a track, so we check both for the 'name'
                for result in allResults {
    
                    var title = result["trackName"] as? String
                    if title == nil {
                        title = result["collectionName"] as? String
                    }
                    if title == nil {
                        title = result["collectionName"] as? String
                    }
                    let previewURL = result["previewUrl"] as? String ?? ""
                    let collectionID = result["collectionId"] as? Int ?? 0
    
                    var newSong = Song(title: title!, previewURL: previewURL, collectionID: collectionID)
                    songs.append(newSong)
                }
            }
            return songs
        }
    
    }
    

    最后是AlbumViewController:

    import UIKit
    import CoreData
    
    class AlbumViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, searchAPIControllerProtocol, songAPIControllerForCoreDataProtocol {
    
        @IBOutlet
        var tableView: UITableView!
    
        @IBOutlet weak var artistNameOutlet: UILabel!
    
        var songapi : songAPIControllerForCoreData?
        var api : searchAPIController?
        var albums = [Album]()
        var songs = [Song]()
        var imageCache = [String : UIImage]()
    
        //Variables that take the values after segue from uTableViewController
        var artistID, artistName: String?
    
        let cellIdentifier: String = "albumCell"
    
        //for CoreData
        var error:NSError?
        let managedObjectContext = (UIApplication.sharedApplication().delegate
            as! AppDelegate).managedObjectContext
    
        func numberOfSectionsInTableView(tableView: UITableView) -> Int {
            // #warning Potentially incomplete method implementation.
            // Return the number of sections.
            return 1
        }
    
        func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return self.albums.count
        }
    
        func download(sender: AnyObject){
            var senderButton : UIButton = sender as! UIButton
            let newAlbum = NSEntityDescription.insertNewObjectForEntityForName("Albums", inManagedObjectContext: managedObjectContext!) as! Albums
            let newSong = NSEntityDescription.insertNewObjectForEntityForName("Songs", inManagedObjectContext: managedObjectContext!) as! Songs
    
            songapi!.searchItunesForSongsBelongingTo((String)(self.albums[senderButton.tag].collectionID))
    
            newAlbum.albumArt = self.albums[senderButton.tag].largeImageURL
            newAlbum.albumID = (String)(self.albums[senderButton.tag].collectionID)
            newAlbum.albumName = self.albums[senderButton.tag].title
            newAlbum.albumPrice = self.albums[senderButton.tag].price
            newAlbum.artistID = self.artistID!
            newAlbum.artistName = self.artistName!
            newAlbum.numberOfSongs = (String)(self.albums[senderButton.tag].trackCount)
            newAlbum.has = []
    
            println(self.songs)
    
            for(var i = 1; i < self.albums[senderButton.tag].trackCount - 1; i++){
                newSong.collectionID = String(self.songs[i].collectionID)
                newSong.previewURL = self.songs[i].previewURL
                newSong.songName = self.songs[i].title
            }
    
            self.managedObjectContext?.save(&self.error)
            println(newAlbum)
        }
    
        func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    
            let cell: AlbumTableViewCell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as! AlbumTableViewCell
    
            cell.albumCellButton.tag = indexPath.row
            cell.albumCellButton.addTarget(self, action: "download:", forControlEvents: .TouchUpInside)
    
            let album = self.albums[indexPath.row]
            cell.albumName.text = album.title
            cell.artistImage.image = UIImage(named: "user7.png")
            cell.numberOfSongs.text = (String)(album.trackCount) + " Songs"
    
    
            // Get the formatted price string for display in the subtitle
            let formattedPrice = album.price
    
            // Grab the artworkUrl60 key to get an image URL for the app's thumbnail
            let urlString = album.thumbnailImageURL
    
            // Check our image cache for the existing key. This is just a dictionary of UIImages
            var image = self.imageCache[urlString]
    
    
            if( image == nil ) {
                // If the image does not exist, we need to download it
                var imgURL: NSURL = NSURL(string: urlString)!
    
                // Download an NSData representation of the image at the URL
                let request: NSURLRequest = NSURLRequest(URL: imgURL)
                NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: {(response: NSURLResponse!,data: NSData!,error: NSError!) -> Void in
                    if error == nil {
                        image = UIImage(data: data)
    
                        // Store the image in to our cache
                        self.imageCache[urlString] = image
                        dispatch_async(dispatch_get_main_queue(), {
                            if let cellToUpdate = tableView.cellForRowAtIndexPath(indexPath) as?AlbumTableViewCell {
                                cellToUpdate.artistImage.image = image
                            }
                        })
                    }
                    else {
                        println("Error: \(error.localizedDescription)")
                    }
                })
    
            }
            else {
                dispatch_async(dispatch_get_main_queue(), {
                    if let cellToUpdate = tableView.cellForRowAtIndexPath(indexPath) as?AlbumTableViewCell {
                        cellToUpdate.artistImage.image = image
                    }
                })
            }
    
            cell.priceOfAlbum.text = formattedPrice
    
            return cell
        }
    
        func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    
        }
    
        func didReceiveAPIResults(results: NSDictionary) {
            var resultsArr: NSArray = results["results"] as! NSArray
            dispatch_async(dispatch_get_main_queue(), {
                self.albums = Album.albumsWithJSON(resultsArr)
                self.tableView!.reloadData()
                UIApplication.sharedApplication().networkActivityIndicatorVisible = false
            })
        }
    
        func didReceiveAPISongResults(results: NSDictionary) {
            var resultsArr: NSArray = results["results"] as! NSArray
            dispatch_async(dispatch_get_main_queue(), {
                self.songs = Song.songsWithJSON(resultsArr)
                self.tableView!.reloadData()
                UIApplication.sharedApplication().networkActivityIndicatorVisible = false
            })
        }
    
        override func viewDidLoad() {
            super.viewDidLoad()
            self.navigationItem.title = artistName
            artistNameOutlet.text = " Albums"
    
            api = searchAPIController(delegate: self)
            songapi = songAPIControllerForCoreData(delegate: self)
    
            UIApplication.sharedApplication().networkActivityIndicatorVisible = true
    
            api!.searchItunesForAlbumsBelongingTo(self.artistName!, id: self.artistID!)
    
            // Do any additional setup after loading the view.
        }
    
        override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    
            let songsController = segue.destinationViewController as! SongsViewController
    
            var albumCollectionID = self.albums
            var albumIndex = tableView!.indexPathForSelectedRow()!.row
            var collectionID = self.albums[albumIndex].collectionID
            var albumName = self.albums[albumIndex].title
    
            songsController.albumName = albumName
            songsController.collectionID = collectionID
    
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    
    }
    

1 个答案:

答案 0 :(得分:0)

您需要编写协议的定义,如下所示:

protocol songAPIControllerForCoreDataProtocol : class {
    func didReceiveAPISongResults(results: NSDictionary)
}

这将使其成为仅类协议,并将强制确认类型具有引用语义。如果没有&#39; class&#39;指定了关键字,它将具有值语义。

没有&#39;班级&#39;关键字这里的问题我假设是通过初始化程序设置委托。当您传递委托时:

songapi = songAPIControllerForCoreData(delegate: self)

这将假定委托参数为值类型并复制值而不是发送它的引用。因此,当您在init()中设置该值时,委托成员将指向一个新对象,而不是传递给UIViewController。

如果您将代理设置为:

songapi.delegate = self

它可以在没有&#39;类的情况下工作。协议定义中的关键字。