Swift 同步网络请求
Posted
技术标签:
【中文标题】Swift 同步网络请求【英文标题】:Swift synchronise network request 【发布时间】:2017-12-13 10:31:39 【问题描述】:我正在获取用户的输入并为其创建 CoreData 实体,然后放入 tableView,但在我需要通过发出几个网络请求来为实体指定一些属性之前。还有一个问题。第一个实体始终为零(并为表格视图创建一个空单元格)但如果我保存上下文并再次打开应用程序 - 在这里,实体就可以了。如果我创建第二个(等等)实体,它工作正常。它似乎也像表格总是为开始创建一个空单元格然后删除它并创建正确的单元格...... 我不明白为什么完成处理程序不能正常工作并且网络请求是异步的。请帮我理解。
创建方法从textFieldShouldReturn
开始
import UIKit
import CoreData
class ViewController: UIViewController, UITextFieldDelegate
var managedObjectContext: NSManagedObjectContext?
lazy var fetchedResultsController: NSFetchedResultsController<Word> =
let fetchRequest: NSFetchRequest<Word> = Word.fetchRequest()
let createdSort = NSSortDescriptor(key: "created", ascending: false)
let idSort = NSSortDescriptor(key: "id", ascending: false)
fetchRequest.sortDescriptors = [createdSort, idSort]
var fetchedResultsController = NSFetchedResultsController(
fetchRequest: fetchRequest,
managedObjectContext: AppDelegate.viewContext,
sectionNameKeyPath: nil,
cacheName: nil)
fetchedResultsController.delegate = self
return fetchedResultsController
()
private var hasWords: Bool
guard let fetchedObjects = fetchedResultsController.fetchedObjects else return false
return fetchedObjects.count > 0
let creator = WordManager.shared
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var messageLabel: UILabel!
override func viewDidLoad()
super.viewDidLoad()
managedObjectContext = AppDelegate.viewContext
fetchWords()
updateView()
func updateView()
tableView.isHidden = !hasWords
messageLabel.isHidden = hasWords
............
func textFieldShouldReturn(_ textField: UITextField) -> Bool
guard let managedObjectContext = managedObjectContext else return false
guard let title = textField.text, !title.isEmpty, !title.hasPrefix(" ") else
showAllert(title: "Warning!", message: "Title may not to be nil!")
return false
let word = Word(context: managedObjectContext)
guard let fetchedWordsCount = fetchedResultsController.fetchedObjects?.count else return false
creator.createWord(title: title, counter: fetchedWordsCount, word: word)
self.updateView()
textField.text = nil
return true
func fetchWords()
do
try fetchedResultsController.performFetch()
catch
fatalError("Cant fetch words. Error \(error.localizedDescription)")
创建实体
import CoreData
import UIKit
class WordManager
static var shared = WordManager()
private init()
private var api = DictionaryAPI()
private var api2 = MeaningAPI()
func createWord(title: String, counter: Int, word: Word)
self.api.fetch(word: title, completion: translation in
self.api2.fetchTranscription(word: title, completion: transcription in
word.id = Int16(counter) + 1
word.title = title
word.translation = translation
word.transcription = "[\(transcription)]"
word.created = NSDate()
)
)
tableView 没什么有趣的
extension ViewController: UITableViewDataSource
func numberOfSections(in tableView: UITableView) -> Int
guard let sections = fetchedResultsController.sections else return 0
return sections.count
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
guard let section = fetchedResultsController.sections?[section] else return 0
return section.numberOfObjects
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: "mainCell", for: indexPath) as! MainCell
let word = fetchedResultsController.object(at: indexPath)
cell.configure(with: word)
return cell
配置单元格方法
func configure(with word: Word)
titleField.text = word.title
translationField.text = word.translation
transcriptionLabel.text = word.transcription
totalCounter.text = "\(word.showCounter)"
correctCounter.text = "\(word.correctCounter)"
wrongCounter.text = "\(word.wrongCounter)"
获取结果委托
extension ViewController: NSFetchedResultsControllerDelegate
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)
tableView.beginUpdates()
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)
tableView.endUpdates()
updateView()
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?)
switch type
case .delete:
guard let indexPath = indexPath else return
tableView.deleteRows(at: [indexPath], with: .fade)
case .insert:
guard let indexPath = newIndexPath else return
tableView.insertRows(at: [indexPath], with: .fade)
case .move:
guard let indexPath = indexPath else return
tableView.deleteRows(at: [indexPath], with: .fade)
guard let newIndexPath = newIndexPath else return
tableView.insertRows(at: [newIndexPath], with: .fade)
default:
break
【问题讨论】:
【参考方案1】:问题:
您在核心数据中的数据未处于可以在应用中显示的状态。NSFetchedResultsController
恰好选择了这些数据并将其显示在应用程序中。
方法:
当用户创建记录时,用户希望立即在应用程序中看到更改,而不必等待应用程序在服务器中更新以查看更改。因此,即使没有网络连接,用户仍然可以创建记录。 从视图上下文创建子上下文 在将记录更新到子上下文时,使用后台线程上传到服务器。 仅当数据处于一致状态时才保存子上下文。NSFetchedResultsController
应该使用视图上下文,因此不会知道子上下文记录。
当您保存子上下文时,NSFetchedResultsController
会选择这些记录。
【讨论】:
问题是我不需要 CoreData 中的不良记录。以上是关于Swift 同步网络请求的主要内容,如果未能解决你的问题,请参考以下文章