ferryawijayanto
ferryawijayanto

Reputation: 649

Encapsulated core data object

I have a json data save in core data and save it in an array, and I want to encapsulated the array I have save in core data. the problem is when I want to display it in app it only retrieve 1 data in array. which is suppose I have a 5. here I show my code

this is a my function fetch request my json data

APIServices.shared.fetchData(url: APIServices.youtubeBaseURL, params: params, of: Item.self) { (items) in
            let privateContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
            privateContext.parent = CoreDataManager.shared.persistenceContainer.viewContext

            var newVideos = [Video]()
            items.forEach({ (item) in
                let video = Video(context: privateContext)
                video.title = item.snippet.title
                video.videoId = item.id.videoId

                newVideos.append(video)

                do {
                    try privateContext.save()
                    try privateContext.parent?.save()

                } catch let saveErr {
                    print("Failed to save json data:", saveErr)
                }
            })
            DispatchQueue.main.async {
                self.videos = newVideos
                self.collectionView.reloadData()
                self.showLoadingHUD()
            }
        }

this is a code in my encapsulated in my collectionViewCell

var video: Video? {
    didSet{
        let context = CoreDataManager.shared.persistenceContainer.viewContext
        let fetchRequest = NSFetchRequest<Video>(entityName: "Video")

        do {
           let videos = try context.fetch(fetchRequest)
            videos.forEach { (video) in
                titleLabel.text = video.title
                guard let videoId = video.videoId else { return }
                DispatchQueue.main.async {
                    let playerVars: [String : Any] = [
                        "playsinline" : 0,
                        "enablejsapi": 1,
                        "wmode": "transparent",
                        "controls": 1,
                        "showinfo": 0,
                        "rel": 0,
                        "modestbranding": 1,
                        "iv_load_policy": 3 //annotations
                    ]
                    self.player.load(withVideoId: videoId, playerVars: playerVars)
                }
            }
        } catch let fetchErr {
            print("Failed to fetch video:", fetchErr)
        }
    }
}

after I fetch the core data and try to print video inside videos.forEach the value is there not only one value. but when I try to load with youtube player, it only display one value.

only one object return

Upvotes: 0

Views: 155

Answers (1)

Bappaditya
Bappaditya

Reputation: 9652

For your solution,

Create a videoModel variable in your UICollectionViewCell class like, and remove fetchRequest call in UICollectionViewCell class which is causing the issue,

var videoModel: VideoModel? {
        didSet {
            titleLabel.text = videoModel?.videoTitle
            let playerVars: [String : Any] = [
                "playsinline" : 0,
                "enablejsapi": 1,
                "wmode": "transparent",
                "controls": 1,
                "showinfo": 0,
                "rel": 0,
                "modestbranding": 1,
                "iv_load_policy": 3 //annotations
            ]
            self.player.load(withVideoId: videoModel?.videoId ?? "", playerVars: playerVars)
        }
    }

ViewModel file should look like,

import Foundation

struct VideoModel {
    var videoTitle: String?
    var videoId: String?

    init(title: String, id: String) {
        videoTitle = title
        videoId = id
    }
}

Then in SearchViewController, create a viewModels array and assign the videoModel your your cell in cellForItemAt datasource method,

var videoModels = [VideoModel]()

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: videoId, for: indexPath) as! SearchVideoCell

        let video = videos[indexPath.row]
        cell.delegate = self
        cell.video = video
        cell.videoModel = videoModels[indexPath.row]

        return cell
    }

Finally in fetchVideosWith append viewModel to your viewModels array,

//MARK:- Fetch Data
    fileprivate func fetchVideosWith(title name: String) {
        let params = ["part": "snippet", "q": "tausiyah \(name)", "key": "AIzaSyC2mn0PTL8JmSWEthvksdJLvsnwo5Tu9BA"]

            APIServices.shared.fetchData(url: APIServices.youtubeBaseURL, params: params, of: Item.self) { (items) in
                let privateContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
                privateContext.parent = CoreDataManager.shared.persistenceContainer.viewContext

                var newVideos = [Video]()
                items.forEach({ (item) in
                    let video = Video(context: privateContext)
                    video.title = item.snippet.title
                    video.videoId = item.id.videoId

                    newVideos.append(video)

                    do {
                        try privateContext.save()
                        try privateContext.parent?.save()
                    } catch let saveErr {
                        print("Failed to save json data:", saveErr)
                    }
                    let videoModel = VideoModel(title: item.snippet.title, id: item.id.videoId)
                    self.videoModels.append(videoModel)
                })
                DispatchQueue.main.async {
                    self.videos = newVideos
                    self.collectionView.reloadData()
                    self.showLoadingHUD()
                }
            }
    }

Hope it helps.

Upvotes: 1

Related Questions