Как добавить в NSSet с использованием Core Data в Swift 5 - PullRequest
1 голос
/ 09 февраля 2020

Итак, я немного больше тренируюсь с основными данными после окончания курса. Так что я все еще немного новичок в этом. Итак, у меня есть 3 сущности с именами Pokemon, Type & Ability. Таким образом, у покемона может быть много типов, таких как огонь, вода, полет и так далее. Тип также может иметь несколько покемонов, которые являются огонь, вода, полет и так далее. То же самое касается Способности, поэтому я установил отношения многие ко многим. Вот как это выглядит.

enter image description here

Я анализирую некоторые JSON формы API и пытаюсь сохранить их в основных данных. Теперь вот где у меня немного проблем. Вот так выглядит мой код, и он в основном анализирует JSON.

struct Service {
static let shared = Service()

func downloadPokemonsFromServer(completion: @escaping ()->()) {
    let urlString = "https://pokeapi.co/api/v2/pokemon?limit=9"
    guard let url = URL(string: urlString) else { return }

    URLSession.shared.dataTask(with: url) { (data, response, error) in
        if let err = error {
            print("Unable to fetch pokemon", err)
        }

        guard let data = data else { return }
        let privateContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
        privateContext.parent = CoreDataManager.shared.persistentContainer.viewContext

        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .convertFromSnakeCase

        do {
            let pokemonJSON = try decoder.decode(PokemonsJSON.self, from: data)
            pokemonJSON.pokemons.forEach { (JSONPokemon) in
               let pokemon = Pokemon(context: privateContext)
                pokemon.name = JSONPokemon.name
                pokemon.url = JSONPokemon.detailUrl

                //Would want to set pokemon types here but
                //When i call fetchMoreDetails(pokemon:,urlString:,completion:)
                //The pokemon is always nil inside fetchMoreDetails
            }

            try privateContext.save()
            try privateContext.parent?.save()
            completion()
        } catch let err {
            print("Unable to decode PokemonJSON. Error: ",err)
            completion()
        }


    }.resume()
}

func fetchMoreDetails(pokemon: Pokemon, urlString: String, completion: @escaping ()->()) {
    guard let url = URL(string: urlString) else { return }


    let privateContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
    privateContext.parent = CoreDataManager.shared.persistentContainer.viewContext

    URLSession.shared.dataTask(with: url) { (data, response, error) in
        if let err = error {
            print("Unable to get more details for pokemon", err)
        }

        guard let data = data else { return }


        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .convertFromSnakeCase

        do {
            let pokemonDetailJSON = try decoder.decode(PokemonDetailJSON.self, from: data)
            pokemonDetailJSON.types.forEach { (nestedType) in
                let type = Type(context: privateContext)
                type.name = nestedType.type.name

                //How do I add type to pokemon.types this does work
                //pokemon.types?.adding(type)

            }

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

            completion()

        } catch let err {
            print("Unable to decode pokemon more details", err)
            completion()
        }

    }.resume()
}
}

Я могу разобрать все нормально и все, но я просто не могу добавить новый тип в pokemons.types , Я смотрел на переполнение стека, но большинство решений, кажется, в Objective C.

Вот так выглядит мой ViewController, и я также использую NSFetchResultController.

class PokemonTableVC: UITableViewController {

lazy var pokemonController: NSFetchedResultsController<Pokemon> = {
    let context = CoreDataManager.shared.persistentContainer.viewContext
    let request: NSFetchRequest<Pokemon> = Pokemon.fetchRequest()
    let nameSort = NSSortDescriptor(key: "name", ascending: true)
    request.sortDescriptors = [nameSort]

    let controller = NSFetchedResultsController(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
    controller.delegate = self
    return controller
}()

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.


    let refreshControl = UIRefreshControl()
    refreshControl.addTarget(self, action: #selector(handleRefresh), for: .valueChanged)
    tableView.refreshControl = refreshControl

    navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Delete", style: .done, target: self, action: #selector(handleDelete))

    try? pokemonController.performFetch()
}

@objc func handleDelete() {
    print("Deleting")
    let context = CoreDataManager.shared.persistentContainer.viewContext

    guard let pokemons = pokemonController.fetchedObjects else { return }
    pokemons.forEach { (pokemon) in
        context.delete(pokemon)
    }

    do {
        try context.save()
    } catch let err {
        print("Unable to save data", err)
    }
}

@objc func handleRefresh() {
    print("DDDDD")
    Service.shared.downloadPokemonsFromServer {
        self.pokemonController.fetchedObjects?.forEach({ (pokemon) in
            print(pokemon.name)
           Service.shared.fetchMoreDetails(pokemon: pokemon, urlString: pokemon.url ?? "") {
                print(pokemon.abilities?.count)

            }
        })
    }
    tableView.refreshControl?.endRefreshing()
}

}

Я могу предоставить другие свои структуры, если это необходимо. Но в основном я пытаюсь добавить тип в pokemon.types также хотел бы добавить fetchMoreDetails, когда я получаю покемонов, где я размещаю комментарий. Буду очень признателен за любые отзывы.

1 Ответ

0 голосов
/ 09 февраля 2020

Когда вы добавляете отношение к объекту, XCode создает методы для получения и установки значений для этого отношения, используя предопределенный стандарт именования. Поэтому в вашем классе Pokemon должны быть некоторые методы для установки экземпляров Type (и здесь может помочь завершение кода):

addToTypes(value:) // single object
addToTypes(values:) //set of objects

Так что в вашем коде это должно быть

pokemon.addToTypes(value: type)

У вас также есть те же методы для типа для противоположного направления

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...