I used core data to make a one to many relationship where the scenario of my application is to display the members for the respected team. Both teams and members are added dynamically.
The issue occurs while storing the data at the member part. The data is getting stored but it won't get displayed in the table view. where I get this error.
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
I have done even a silly mistake as I'm new to core data. I can't figure it out what I'm doing wrong. I will show what I have done, rectify me what I did wrong. Please manipulate my code and give me the answer, no logical or random answers 'coz I don't have enough time to try out every possibilities.Help is very much appreciated, thanks in advance.
ER Model
Team table view 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
}
}
}
Member table view 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.
}
}
To Add teams
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.
}
*/
}
To add members
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.
}
*/
}
Team entity
extension Teams {
@NSManaged var teamImage: NSObject?
@NSManaged var teamName: String?
@NSManaged var members: NSSet?
}
Members entity
extension Members {
@NSManaged var memberDesignation: String?
@NSManaged var memberImage: NSObject?
@NSManaged var memberName: String?
@NSManaged var teams: Teams?
}
I'm very much confused at, how to add the members with respect to the teams?! How could i resolve this? For a better understanding about the scenario you could refer to this question Can I add an NSManagedObject to the selected parent object just using Interface Builder and Core Data? and also you could refer to this https://github.com/pbasdf/DemoMasterDetail which is exactly how I would like my app to produce the output.
member.members = currentTeam
– Hobbema