ios - 存储的数据在 TableView 中无法显示,在核心数据的一对多关系中?

标签 ios swift uitableview core-data master-detail

我使用核心数据来建立一对多关系,我的应用程序场景是显示受人尊敬的团队的成员。团队和成员都是动态添加的。

在成员部分存储数据时出现问题。数据正在存储,但不会显示在 TableView 中。我在哪里收到此错误。

数据:{ 成员名称 = ""; 成员(member)图片=无; 成员(member)名 = bbgbb; 团队=零; }) 为部分名称键路径“Teams.teams”返回了 nil 值。对象将被放置在未命名的部分

我什至犯了一个愚蠢的错误,因为我是核心数据的新手。我不知道我做错了什么。我会展示我所做的,纠正我做错的。请操纵我的代码并给我答案,不要有逻辑或随机答案,因为我没有足够的时间尝试所有可能性。非常感谢您的帮助,提前致谢。

ER 模型

enter image description here

团队 TableView Controller

import UIKit
import CoreData

class GroupTable: UITableViewController, NSFetchedResultsControllerDelegate {

let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext

var teamData = [Teams]()

var fetchedResultsController : NSFetchedResultsController = NSFetchedResultsController()

let statusbarHeight: CGFloat = 20


override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    // #warning Incomplete implementation, return the number of sections
    return 1
}

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.contentInset.top = statusbarHeight
    self.navigationItem.leftBarButtonItem!.image = UIImage(named: "Arrow")?.imageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal)

}

@IBAction func backToLogo(sender: AnyObject) {

    let previous = self.storyboard?.instantiateViewControllerWithIdentifier("Logo")
    self.presentViewController(previous!, animated: true, completion: nil)
}

override func viewWillAppear(animated: Bool) {

    let request = NSFetchRequest(entityName: "Teams")

    do{
        teamData = try managedObjectContext.executeFetchRequest(request) as! [Teams]
    } catch let error as NSError {
        print("\(error), \(error.userInfo)")
    }

    self.tableView.reloadData()

}


override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if teamData.count > 0{

        self.tableView.backgroundView = nil
        return teamData.count

    } else {
        let emptyLabel = UILabel(frame: CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height))
        emptyLabel.text = "No Teams available at the moment, create one!"
        emptyLabel.textAlignment = NSTextAlignment.Center
        self.tableView.backgroundView = emptyLabel
        self.tableView.separatorStyle = UITableViewCellSeparatorStyle.None
        return 0

    }

}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("groupCell", forIndexPath: indexPath) 

    let teamDetails = teamData[indexPath.row]

    cell.textLabel?.text = teamDetails.teamName
    cell.imageView?.image = teamDetails.teamImage as? UIImage
    return cell

}

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    // Get the new view controller using segue.destinationViewController.
    // Pass the selected object to the new view controller.
    if segue.identifier == "memberView" {
        let destination = segue.destinationViewController as! MemberTableViewController
        let indexPath = tableView.indexPathForSelectedRow!
        let selectedObject = fetchedResultsController.objectAtIndexPath(indexPath) as! Teams
        destination.currentTeam = selectedObject            
    }
  }  
}

成员 TableView Controller

import UIKit
import CoreData


class MemberTableViewController: UITableViewController, NSFetchedResultsControllerDelegate {

let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext

var memberData = [Members]()

var currentTeam : Teams?

var fetchedResultsController: NSFetchedResultsController!

override func viewDidLoad() {
    super.viewDidLoad()

}

override func viewWillAppear(animated: Bool) {

    let request = NSFetchRequest(entityName: "Members")
    let members = NSSortDescriptor(key: "memberName", ascending: false)
    request.sortDescriptors = [members]
    if let thisTeam = currentTeam {

    request.predicate = NSPredicate(format:"teams == %@",thisTeam)
    }

    let fetchedResults = NSFetchedResultsController(fetchRequest: request, managedObjectContext: managedObjectContext, sectionNameKeyPath: "Teams.members", cacheName: nil)
    fetchedResults.delegate = self

    do {
        try fetchedResults.performFetch()
    } catch {
        fatalError("Failed to initialize FetchedResultsController: \(error)")
    }
    self.tableView.reloadData()

}


override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

// MARK: - Table view data source

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    // #warning Incomplete implementation, return the number of sections
    return 1
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of rows

    if memberData.count > 0{

        self.tableView.backgroundView = nil
        return memberData.count

    } else {
        let emptyLabel = UILabel(frame: CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height))
        emptyLabel.text = "No Members in the team, add one!"
        emptyLabel.textAlignment = NSTextAlignment.Center
        self.tableView.backgroundView = emptyLabel
        self.tableView.separatorStyle = UITableViewCellSeparatorStyle.None
        return 0

    }

}



override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("memberCell", forIndexPath: indexPath) as! ScreenThreeTableViewCell

    // Configure the cell...

    let memberDetails = memberData[indexPath.row]

    cell.memberName?.text = memberDetails.memberName
    cell.memberDesignation?.text = memberDetails.memberDesignation
    cell.memberImage?.image = memberDetails.memberImage as? UIImage

    return cell
}

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {


}

/*
// Override to support conditional editing of the table view.
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
    // Return false if you do not want the specified item to be editable.
    return true
}
*/

/*
// Override to support editing the table view.
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
    if editingStyle == .Delete {
        // Delete the row from the data source
        tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
    } else if editingStyle == .Insert {
        // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
    }    
}
*/

/*
// Override to support rearranging the table view.
override func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {

}
*/

/*
// Override to support conditional rearranging of the table view.
override func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
    // Return false if you do not want the item to be re-orderable.
    return true
}
*/


// MARK: - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    // Get the new view controller using segue.destinationViewController.
    // Pass the selected object to the new view controller.      
  }
}

添加团队

import UIKit
import CoreData

class ScreenTwoPopOverViewController: UIViewController, UIImagePickerControllerDelegate,UINavigationControllerDelegate,UIPopoverControllerDelegate {

@IBOutlet weak var teamNamePO: UITextField!
@IBOutlet weak var teamImagePO: UIImageView!
@IBOutlet weak var selectPicturePO: UIButton!


var picker:UIImagePickerController?=UIImagePickerController()
let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.


}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}
@IBAction func submit(sender: AnyObject) {

    let entity = NSEntityDescription.entityForName("Teams", inManagedObjectContext: managedObjectContext)
    let team = Teams(entity: entity!, insertIntoManagedObjectContext: managedObjectContext)

    team.teamName = teamNamePO.text
    team.teamImage = teamImagePO.image

    do{
        try managedObjectContext.save()
    } catch let error as NSError{
        print("\(error), \(error.userInfo)")
    }

    dismissViewControllerAnimated(true, completion: nil)

}
@IBAction func cancel(sender: AnyObject) {

    dismissViewControllerAnimated(true, completion: nil)
}

@IBAction func btnImagePickerClicked(sender: AnyObject)
{
    let alert:UIAlertController=UIAlertController(title: "Choose Image", message: nil, preferredStyle: UIAlertControllerStyle.ActionSheet)

    let cameraAction = UIAlertAction(title: "Camera", style: UIAlertActionStyle.Default)
        {
            UIAlertAction in
            self.openCamera()

    }
    let gallaryAction = UIAlertAction(title: "Gallary", style: UIAlertActionStyle.Default)
        {
            UIAlertAction in
            self.openGallary()
    }
    let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel)
        {
            UIAlertAction in

    }

    // Add the actions
    picker?.delegate = self
    alert.addAction(cameraAction)
    alert.addAction(gallaryAction)
    alert.addAction(cancelAction)
    // Present the controller
    self.presentViewController(alert, animated: true, completion: nil)
}

func openCamera()
{
    if(UIImagePickerController .isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera))
    {
        picker!.sourceType = UIImagePickerControllerSourceType.Camera
        self .presentViewController(picker!, animated: true, completion: nil)
    }else {
        openGallary()
    }
}

func openGallary()
{
    picker!.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
    self.presentViewController(picker!, animated: true, completion: nil)
}

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject])
{
    picker .dismissViewControllerAnimated(true, completion: nil)
    teamImagePO.image=info[UIImagePickerControllerOriginalImage] as? UIImage
}

func imagePickerControllerDidCancel(picker: UIImagePickerController)
{
    print("picker cancel.")
    self.presentViewController(self, animated: true, completion: nil)
}



/*
// MARK: - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    // Get the new view controller using segue.destinationViewController.
    // Pass the selected object to the new view controller.
}
*/

}

添加成员

import UIKit
import CoreData

class ScreenThreePopOverViewController: UIViewController,UIImagePickerControllerDelegate,UINavigationControllerDelegate,UIPopoverControllerDelegate {

@IBOutlet weak var memberDesignationPO: UITextField!
@IBOutlet weak var memberNamePO: UITextField!
@IBOutlet weak var memberImagePO: UIImageView!

var picker:UIImagePickerController?=UIImagePickerController()
let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext

var currentTeam : Teams?


override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}
@IBAction func selectPicture(sender: AnyObject) {

    let alert:UIAlertController=UIAlertController(title: "Choose Image", message: nil, preferredStyle: UIAlertControllerStyle.ActionSheet)

    let cameraAction = UIAlertAction(title: "Camera", style: UIAlertActionStyle.Default)
        {
            UIAlertAction in
            self.openCamera()

    }
    let gallaryAction = UIAlertAction(title: "Gallary", style: UIAlertActionStyle.Default)
        {
            UIAlertAction in
            self.openGallary()
    }
    let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel)
        {
            UIAlertAction in

    }

    // Add the actions
    picker?.delegate = self
    alert.addAction(cameraAction)
    alert.addAction(gallaryAction)
    alert.addAction(cancelAction)
    // Present the controller
    self.presentViewController(alert, animated: true, completion: nil)
}

func openCamera()
{
    if(UIImagePickerController .isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera))
    {
        picker!.sourceType = UIImagePickerControllerSourceType.Camera
        self .presentViewController(picker!, animated: true, completion: nil)
    }else {
        openGallary()
    }
}

func openGallary()
{
    picker!.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
    self.presentViewController(picker!, animated: true, completion: nil)
}

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject])
{
    picker .dismissViewControllerAnimated(true, completion: nil)
    memberImagePO.image=info[UIImagePickerControllerOriginalImage] as? UIImage
}

func imagePickerControllerDidCancel(picker: UIImagePickerController)
{
    print("picker cancel.")
            dismissViewControllerAnimated(true, completion: nil)
}


@IBAction func cancel(sender: AnyObject) {

    dismissViewControllerAnimated(true, completion: nil)

}
@IBAction func submit(sender: AnyObject) {

    let entity = NSEntityDescription.entityForName("Members", inManagedObjectContext: managedObjectContext)
    let member = Members(entity: entity!, insertIntoManagedObjectContext: managedObjectContext)

    member.memberName = memberNamePO.text
    member.memberDesignation = memberDesignationPO.text
    member.memberImage = memberImagePO.image

if let team  = currentTeam {
        member.teams = team
    }        
    do{
        try managedObjectContext.save()
    } catch let error as NSError{
        print("\(error), \(error.userInfo)")
    }
    dismissViewControllerAnimated(true, completion: nil)


}


/*
// MARK: - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    // Get the new view controller using segue.destinationViewController.
    // Pass the selected object to the new view controller.
}
*/

}

团队实体

extension Teams {

@NSManaged var teamImage: NSObject?
@NSManaged var teamName: String?
@NSManaged var members: NSSet?

}

成员实体

extension Members {

@NSManaged var memberDesignation: String?
@NSManaged var memberImage: NSObject?
@NSManaged var memberName: String?
@NSManaged var teams: Teams?

}

我很困惑,如何为团队添加成员?!我该如何解决这个问题?为了更好地了解该场景,您可以引用这个问题 Can I add an NSManagedObject to the selected parent object just using Interface Builder and Core Data?你也可以引用这个https://github.com/pbasdf/DemoMasterDetail这正是我希望我的应用产生输出的方式。

最佳答案

嗨,Praveen Kumar,你可以这样做:)

@IBAction func submit(sender: AnyObject) {

    let entity = NSEntityDescription.entityForName("Members", inManagedObjectContext: managedObjectContext)
    let member = Members(entity: entity!, insertIntoManagedObjectContext: managedObjectContext)

    member.memberName = memberNamePO.text
    member.memberDesignation = memberDesignationPO.text
    member.memberImage = memberImagePO.image

     member.setValue(currentTeam, forKey: "teams") //mistake you did is you were trying to set the wrong relationship :) member has a relationship to teams and is called teams. So you can access member.teams not member.members 

    //or
    member.teams = currentTeam

    do{
        try managedObjectContext.save()
    } catch let error as NSError{
        print("\(error), \(error.userInfo)")
    }
    dismissViewControllerAnimated(true, completion: nil)


}

提示

关系名称应该清楚地说明两个实体之间的联系。而不是简单地给出像成员和团队这样的名字,而是一个更明智的名字:)

团队 -> 包含 -> 成员 成员 -> Belongs_To -> 团队

因此,Team 实体应该与名称为 Contains 的 Members 具有一对多关系。所以当一个人看到它并阅读它时,它将是 Team contains members :)

同样,Members 实体应该与名称为 Belongs_To 的 Teams 具有一对一的关系。所以当一个人看到它并阅读它时,它将成为属于团队的成员:)

希望我的回答对你有帮助:)

关于ios - 存储的数据在 TableView 中无法显示,在核心数据的一对多关系中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37074847/

相关文章:

c# - iOS 上的 Unity 5.1 序列化 - 尚不支持 IL2CPP 文件名

ios - 有什么办法可以实时预览 AVMutableComposition 吗?如果不是,Final Cut Pro 是如何做到的?

swift - 设置内容offest,隐藏表格

ios - 如何在我的 iOS 应用程序中每 n 分钟更新一次后台位置?

ios - Spritekit-如何在受到重力时水平翻转 Sprite

ios - 当内容大小改变时展开 UITableViewCell

ios - 从 API 转换 Swift 中字符串中的任何 UTF-8 编码字符

swift - Swift 中的正则表达式不能完全工作

ios - 在任何滚动或表格重新加载后,在 TableView 中使用计时器重新创建计时器

ios - 我应该为应用程序中的每个表创建一个 UITableViewCell 类吗?