存储的数据无法在表视图中显示核心数据的一对多关系?

时间:2016-05-06 14:22:32

标签: ios swift uitableview core-data master-detail

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

将数据存储在成员部分时会出现问题。数据已存储但不会显示在表视图中。我在哪里得到这个错误。

data: { memberDesignation = ""; memberImage = nil; memberName = bbgbb; teams = nil; }) returned nil value for section name key path 'Teams.teams'. Object will be placed in unnamed section

由于我是核心数据的新手,我甚至犯了一个愚蠢的错误。我无法弄明白我做错了什么。我将展示我的所作所为,纠正我的错误。请操纵我的代码并给我答案,没有逻辑或随机答案'因为我没有足够的时间来尝试各种可能性。非常感谢帮助,提前感谢。

ER模型

enter image description here

团队表视图控制器

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            
    }
  }  
}

会员表视图控制器

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,这正是我希望我的应用程序产生输出的方式。

1 个答案:

答案 0 :(得分:1)

嗨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 - >队

因此,团队实体应该将一对多关系发送给名为Contains的成员。因此,当人们看到并阅读时,团队将包含成员:​​)

同样,会员实体应该与名为Belongs_To的团队建立一对一关系。因此,当一个人看到它并读取它将成为属于团队的成员:))

希望我的回答能帮到你:)。