- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我正在尝试使用 CoreData 实现一个 tableView。该表有四种排序方式。我在实现前三个方面没有问题,但第四个不同,因为它是一个有关系的实体。在我可以添加项目的第二个 View Controller 中,我添加了获取现有项目信息并将它们显示在相关单元格中的功能。
该应用程序有 2 个 View Controller ,一个用于 tableView,另一个用于添加/编辑 tableView 正在查看的项目。接下来是两个类:
import UIKit
import CoreData
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, NSFetchedResultsControllerDelegate{
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var segment: UISegmentedControl!
var controller: NSFetchedResultsController<Item>!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
//self.tableView.register(ItemCell.self, forCellReuseIdentifier: "ItemCell")
generateData()
attemptFetchRequest()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 150
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let sections = controller.sections {
let sectionInfo = sections[section]
return sectionInfo.numberOfObjects
}
return 0
}
func numberOfSections(in tableView: UITableView) -> Int {
if let sections = controller.sections {
return sections.count
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "itemCell", for: indexPath) as! ItemCell
configureCell(cell: cell, indexPath: indexPath as NSIndexPath)
return cell
}
func configureCell (cell: ItemCell, indexPath: NSIndexPath) {
let item = controller.object(at: indexPath as IndexPath)
cell.configCell(item: item)
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let objs = controller.fetchedObjects , objs.count > 0 {
let item = objs[indexPath.row]
performSegue(withIdentifier: "ItemVC", sender: item)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ItemVC" {
if let destination = segue.destination as? ItemVC {
if let item = sender as? Item {
destination.itemtoEdit = item
}
}
}
}
func attemptFetchRequest() {
let fetchrequest: NSFetchRequest = Item.fetchRequest()
let dateSort = NSSortDescriptor(key: "created", ascending: false)
let priceSort = NSSortDescriptor(key: "price", ascending: true)
let alphabetSort = NSSortDescriptor(key: "title", ascending: true)
let typeSort = NSSortDescriptor(key: "toItemType.type", ascending: true)
if segment.selectedSegmentIndex == 0 {
fetchrequest.sortDescriptors = [dateSort]
}else if segment.selectedSegmentIndex == 1 {
fetchrequest.sortDescriptors = [priceSort]
}else if segment.selectedSegmentIndex == 2 {
fetchrequest.sortDescriptors = [alphabetSort]
}else if segment.selectedSegmentIndex == 3{
fetchrequest.sortDescriptors = [typeSort]
}
let controller = NSFetchedResultsController(fetchRequest: fetchrequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
controller.delegate = self
self.controller = controller
do{
try controller.performFetch()
} catch {
let error = error as NSError
print("\(error)")
}
}
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.beginUpdates()
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.endUpdates()
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
switch (type) {
case .insert:
if let indexPath = newIndexPath{
tableView.insertRows(at: [indexPath], with: .fade)
}
break
case .delete:
if let indexPath = indexPath {
tableView.deleteRows(at: [indexPath], with: .fade)
}
break
case .update:
if let indexPath = indexPath {
>>let cell = tableView.cellForRow(at: indexPath) as! ItemCell
configureCell(cell: cell, indexPath: indexPath as NSIndexPath)
}
break
case .move:
if let indexPath = indexPath {
tableView.deleteRows(at: [indexPath], with: .fade)
}
if let indexPath = newIndexPath {
tableView.insertRows(at: [indexPath], with: .fade)
}
break
}
}
@IBAction func segmentChanged(_ sender: AnyObject) {
attemptFetchRequest()
tableView.reloadData()
}
func generateData() {
let item1 = Item(context: context)
item1.title = "Car of the cars"
item1.price = 100000
item1.details = "Nothing much to say, it's a crapy car, don't buy it"
let item2 = Item(context: context)
item2.title = "Rocket"
item2.price = 50000
item2.details = "It's not fast as the actual rocket, but still faster than a bicycle"
let item3 = Item(context: context)
item3.title = "bal bla bla"
item3.price = 50
item3.details = "The price talks!"
let item4 = Item(context: context)
item4.title = "Old is Gold"
item4.price = 60000000
item4.details = "It's old, but also considered as great inheritance"
}
}
和第二个 View Controller 的类:
import UIKit
import CoreData
class ItemVC: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
@IBOutlet weak var storesPicker: UIPickerView!
@IBOutlet weak var name : UITextField!
@IBOutlet weak var price : UITextField!
@IBOutlet weak var details : UITextField!
@IBOutlet weak var image: UIImageView!
var stores = [Store]()
var types = [ItemType]()
var itemtoEdit: Item?
var imagePicker: UIImagePickerController!
override func viewDidLoad() {
super.viewDidLoad()
if let topItem = self.navigationController?.navigationBar.topItem {
topItem.backBarButtonItem = UIBarButtonItem(title: "", style: UIBarButtonItemStyle.plain, target: nil, action: nil)
}
storesPicker.delegate = self
storesPicker.dataSource = self
imagePicker = UIImagePickerController()
imagePicker.delegate = self
generateData()
fetchRequest()
if itemtoEdit != nil {
loadData()
}
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
var returnValue = 0
switch component {
case 0:
returnValue = stores.count
case 1:
returnValue = types.count
default:
break
}
return returnValue
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 2
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
var returnValue : String!
switch component {
case 0:
returnValue = stores[row].name
case 1:
returnValue = types[row].type
default:
break
}
print(returnValue)
return returnValue
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
//update
}
func fetchRequest (){
let storefetch : NSFetchRequest<Store> = Store.fetchRequest()
let typefetch : NSFetchRequest<ItemType> = ItemType.fetchRequest()
do {
self.stores = try context.fetch(storefetch)
self.types = try context.fetch(typefetch)
self.storesPicker.reloadAllComponents()
} catch {
//print("fetch error")
}
}
@IBAction func saveItem(_ sender: AnyObject) {
var item : Item!
let pic = Image(context: context)
pic.image = image.image
if itemtoEdit == nil {
item = Item(context: context)
} else {
item = itemtoEdit
}
item.toImage = pic
if let title = name.text{
item.title = title
}
if let price = price.text {
item.price = (price as NSString).doubleValue
}
if let details = details.text {
item.details = details
}
item.toStore = stores[storesPicker.selectedRow(inComponent: 0)]
>>item.toItemType = types[storesPicker.selectedRow(inComponent: 1)]
ad.saveContext()
_ = navigationController?.popViewController(animated: true)
//dismiss(animated: true, completion: nil)
}
func loadData() {
if let item = itemtoEdit {
name.text = item.title
price.text = "\(item.price)"
details.text = item.details
image.image = item.toImage?.image as? UIImage
if let store = item.toStore {
var index = 0
repeat{
if store.name == stores[index].name {
storesPicker.selectRow(index, inComponent: 0, animated: false)
}
index += 1
} while(index < stores.count)
}
if let type = item.toItemType {
var index = 0
repeat{
if type.type! == types[index].type! {
storesPicker.selectRow(index, inComponent: 1, animated: false)
}
index += 1
} while(index < types.count)
}
}
}
@IBAction func deleteItem(_ sender: UIBarButtonItem) {
if itemtoEdit != nil {
context.delete(itemtoEdit!)
ad.saveContext()
}
_ = navigationController?.popViewController(animated: true)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let img = info[UIImagePickerControllerOriginalImage] as? UIImage {
image.image = img
}
imagePicker.dismiss(animated: true, completion: nil)
}
@IBAction func setImg(_ sender: AnyObject) {
present(imagePicker, animated: true, completion: nil)
}
func generateData(){
let store1 = Store(context: context)
store1.name = "Karfour"
let store2 = Store(context: context)
store2.name = "خير زمان"
let store3 = Store(context: context)
store3.name = "BestBuy"
let store4 = Store(context: context)
store4.name = "Virgin"
let store5 = Store(context: context)
store5.name = "Max"
let type1 = ItemType(context: context)
type1.type = "eletronics"
let type2 = ItemType(context: context)
type2.type = "food"
let type3 = ItemType(context: context)
type3.type = "wears"
let type4 = ItemType(context: context)
type4.type = "books"
let type5 = ItemType(context: context)
type5.type = "weapons"
ad.saveContext()
}
}
我测试了这个错误,发现它从函数返回 nill :
let cell = tableView.cellForRow(at: indexPath) as! ItemCell
我非常确定导出并以正确的方式设置自定义类,所以我测试并注意到当我删除某行时,错误不再显示。我注意到的另一件事是,当我第一次在模拟器中运行该应用程序时,没有存储该应用程序的数据,即使使用之前导致问题的行,它也能完全正常工作,但在那之后,当我重新运行时问题显示的应用程序。 我搜索了使 cellForRow 的返回值成为 will 的原因,但找不到任何有用的信息。我希望你能帮助我。提前致谢。
已解决使用 if let 展开“cell”,如下所示:
case .update:
if let indexPath = indexPath {
if let cell = tableView.cellForRow(at: indexPath) as? ItemCell {
configureCell(cell: cell, indexPath: (indexPath as NSIndexPath))
}
}
break
最佳答案
根据您的描述,我认为这是正在发生的事情:
您点击 ViewController
中的一个单元格,然后转到 ItemVC
。保存项目时,将调用获取的结果 Controller 委托(delegate)方法。在该方法中,您使用 cellForRow(at:)
获取与已更新的 Item
对应的单元格。现在,该行必须可见(尽管在 ItemVC
的“后面”)——否则您还能如何点击它? - 所以 cellForRow(at:)
返回您需要配置的单元格。
这就是您的代码的工作方式,并且一切似乎都正常,直到您添加了更新关系的行:
item.toItemType = types[storesPicker.selectedRow(inComponent: 1)]
您说从ItemType
到Item
的关系是一对一的。假设您有一个与“食物”ItemType
相关的 itemA
。在您的 ViewController 中,您点击不同项目的单元格 - itemB
。在 ItemVC
中,您更新了 itemB
的属性并将其分配给“食物”ItemType
。但是每个 ItemType
只能与一个 Item
相关。因此从 itemA
到“食物”ItemType
的关系被移除。这意味着 itemA
的 toItemType
值设置为 nil。所以有两个 Item
对象受到影响:
itemA
将其 toItemType
设置为 nil,并且 itemB
将其 toItemType
设置为“食物”ItemType
。这两个更新都会被 FRC 观察到,并且会为每个更新调用委托(delegate)方法。在 itemB
的情况下,一切都像以前一样正常工作 - 它是被点击的单元格,因此它必须是可见的。但在 itemA
的情况下,它可能会或可能不会可见。如果它不可见,cellForRow(at:)
返回 nil,您的原始代码就会崩溃。通过在 cell
上使用可选绑定(bind),您可以避免崩溃。相应的行没有更新,但没关系:无论如何它都不可见,当它在屏幕上滚动时,它将被正确配置为正常处理的一部分。
关键在于,因为从 ItemType
到 Item
的关系是一对一的,所以每当您在 ItemVC
。我认为您可能希望建立这种关系。然后将
itemB
添加到“食物”ItemType
将不会对 itemA
产生任何影响:它们都可能与其相关。
关于ios - tableView.cellForRow(在 : indexPath) returns nil?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39990672/
在检查对象是否为 nil 时,有人使用 1: if (object == nil) { //... } 有人用 2: if (nil == object) { //... } 1和2有
func InsertApData(w http.ResponseWriter, r *http.Request) { decoder := json.NewDecoder(r.Body)
为什么 nil.to_s 返回 "",而 nil.inspect 返回 "nil"(当显然 .inspect 使用 .to_s 方法) 最佳答案 "inspect" method of the Obj
运行时间 https://play.golang.org/p/sl12vfS9vP package main import "fmt" func main() { err := run()
我可以将三元条件运算符用于 if {} else {} 语句,如下所示:a ? x : y,还是问题?回答 1 : 回答 2。 是否可以使用这种格式来检查,而不是 a 是 true 还是 false,
无法弄清楚这里出了什么问题。按照设计设置说明,用谷歌搜索我能想到的一切,仍然没有运气。 undefined method `email' for # Extracted source (around
今天写一些 rspec 时,我遇到了一些意外的行为,将日期(和时间)实例与 nil 进行比较。这是一个使用原始 ruby 的示例(没有 Rails 或其他库): user@MacBook-Work
我将数据类型的非零值分配给非可选属性,然后将其分配给可选属性,最后用所述数据实例化图像。当可选项通过 if-let 子句时,它的 block 执行,抛出错误: Fatal error: Unexpec
swift 5.1 。 考虑以下。 let x: Any? = nil let y: Any = x print("x \(x)") // x nil pri
请耐心听我解释这一点, 我正在创建一个聊天室,用户可以在其中上传照片供其他人查看。当用户点击图标时,他们可以将照片上传到我的 Firebase 数据库(这已成功完成,我已经对此进行了测试)。照片的 U
我的 xCode 5.0 目前遇到一个奇怪的问题:一个对象在控制台中似乎为 nil,但同时它可以通过代码访问。 图 1:对象似乎为零 图2:NSLog(@"%@", imgDownloader) 的输
我有一个实现协议(protocol)的类,以便添加 3 个变量。我专门设置了图像变量,调试器显示该变量存在,但是在我打印它时在代码中显示为 nil,我的 if let 语句也认为该变量为 nil。 @
这个问题在这里已经有了答案: Swift 2 ( executeFetchRequest ) : error handling (5 个答案) 关闭 7 年前。 开始在 SWIFT 中学习编码,每次
两者 (not 'nil) 和 (not nil) 求值为T,那么'nil和nil有什么区别吗?那么 ''nil 呢?如果 ''nil 的计算结果为 'nil,那么 ''nil 是否也应该计算为 ni
(if '(nil nil) 'print-true 'print-false) (if '(nil) 'print-true 'print-false) 在上面的代码
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: obj.nil? vs. obj == nil 我发现了一个问题 - == nil 和 nil 哪个更好?
此代码段抛出异常: x = nil jsoned = x.to_json puts 'x.to_json=' + jsoned.inspect puts 'back=' + JSON.parse(js
基本上我有一个对象想要传递给前端。我在后端记录了它,它不是空的,但是在前端,当我提醒它时,它变成了空。 ... presentation := &presentationStruct { Obje
我创建了一个自定义错误类型来包装错误,以便在 Golang 中更轻松地进行调试。当有错误要打印时它可以工作,但现在它会引起 panic 。 Demo type Error struct { E
写一个符合我当前问题的标题有点难..我有一个 main() 函数,它使用另一个包 (database_sql) 中的函数。该函数初始化一个全局变量 sql.DB*。初始化后,变量不为nil,但是对于其
我是一名优秀的程序员,十分优秀!