UIPickerView + Основные данные
ОБНОВЛЕНИЕ С ОТВЕТОМ
import UIKit
import CoreData
class ExerciseViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UIPickerViewDataSource, UIPickerViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
VDL()
//sets stepper configs
setsStepper.wraps = false
setsStepper.autorepeat = true
setsStepper.continuous = true
setsStepper.tintColor = UIColor.redColor()
setsStepper.minimumValue = 0
setsStepper.maximumValue = 500
setsStepper.value = 0
//reps stepper configs
repsStepper.wraps = false
repsStepper.autorepeat = true
repsStepper.continuous = true
repsStepper.tintColor = UIColor.orangeColor()
repsStepper.minimumValue = 0
repsStepper.maximumValue = 500
repsStepper.value = 0
exerciseTableView.reloadData()
}
var moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
var fetchedResultsController: NSFetchedResultsController?
@IBOutlet var exerciseTableView: UITableView!
@IBOutlet var daysPickerView: UIPickerView!
@IBOutlet var exerciseName: UITextField!
@IBOutlet var setsStepper: UIStepper!
@IBOutlet var repsStepper: UIStepper!
@IBOutlet var setsNumber: UILabel!
@IBOutlet var repsNumber: UILabel!
var namesArray = [String]()
var setsArray = [Int]()
var repsArray = [Int]()
var daysArray = [TrainingDay]()
var detailsArray = [TrainingDetails]()
func VDL () {
let fetchRequest = NSFetchRequest(entityName: "TrainingDay")
let sort = NSSortDescriptor(key: "dayIndex", ascending: true)
fetchRequest.sortDescriptors = [sort]
daysArray = (moc!.executeFetchRequest(fetchRequest, error: nil) as? [TrainingDay])!
if daysArray.count == 0 { // nothing there
let dayEntity = NSEntityDescription.entityForName("TrainingDay", inManagedObjectContext: moc!)
let days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
for (index, name) in enumerate(days) {
let newDay = TrainingDay(entity: dayEntity!, insertIntoManagedObjectContext: moc)
newDay.day = name
newDay.dayIndex = index
daysArray.append(newDay)
}
var error: NSError?
moc!.save(&error)
}
}
func appendTrainingDetailsToArray () {
let nameLabel = exerciseName.text
namesArray.append(nameLabel)
let numberOfSets = setsNumber.text?.toInt()
setsArray.append(numberOfSets!)
let numberOfReps = repsNumber.text?.toInt()
repsArray.append(numberOfReps!)
let row = daysPickerView.selectedRowInComponent(0)
let currentDay = daysArray[row]
let detailsEntity = NSEntityDescription.entityForName("TrainingDetails", inManagedObjectContext: moc!)
let trainingdetails = TrainingDetails(entity: detailsEntity!, insertIntoManagedObjectContext: moc)
trainingdetails.trainingDay = currentDay
var error: NSError?
moc?.save(&error)
if let err = error {
var status = err.localizedFailureReason
println("\(status)")
} else {
println("CURRENT SETTING: \(trainingdetails.trainingDay)")
}
}
@IBAction func doneButton(sender: AnyObject) {
appendTrainingDetailsToArray()
exerciseTableView.reloadData()
}
@IBAction func setsStepperAction(sender: UIStepper) {
println("\(Int(sender.value))")
setsNumber.text = Int(sender.value).description
}
@IBAction func repsStepper(sender: UIStepper) {
println("\(Int(sender.value))")
repsNumber.text = Int(sender.value).description
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return namesArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "exerciseCell"
var cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as? UITableViewCell
if cell == nil {
cell = UITableViewCell(style: UITableViewCellStyle.Value2, reuseIdentifier: cellIdentifier)
}
let row = indexPath.row
println("\(row)")
let details = detailsArray[indexPath.row]
cell!.textLabel!.text = details.exerciseName
cell?.detailTextLabel?.text = "Sets: #\(details.setsNumber) Reps: #\(details.repsNumber)"
return cell!
}
//PICKER VIEW DELEGATE AND DATASOURCE METHODS
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return daysArray.count
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
let trainingDay = daysArray[row]
return trainingDay.day
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
let currentDay = daysArray[row]
let fetchRequest = NSFetchRequest(entityName: "TrainingDetails")
let predicate = NSPredicate(format: "trainingDay = %@", currentDay)
fetchRequest.predicate = predicate
let sort = NSSortDescriptor(key: "exerciseName", ascending: true)
fetchRequest.sortDescriptors = [sort]
detailsArray = (moc!.executeFetchRequest(fetchRequest, error: nil) as? [TrainingDetails])!
exerciseTableView.reloadData()
}
}
Ранее я попросил помощи, чтобы я мог адаптироваться с UIPickerView. Как сказал @pbasdf, код нуждался в некоторых корректировках, чтобы соответствовать основным данным и представлению выбора. Вы можете увидеть его объяснение в его ответе!
2 ответа
Есть несколько вещей для решения:
Сущность TrainingDay
Вы ошиблись с awakeFromInsert
код. Он не вставляет новые объекты; он запускается всякий раз, когда вы вставляете новый TrainingDay
объект. Из того, что я вижу в вашем коде, вы фактически никогда не вставляете новые TrainingDays (что повезло, потому что awakeFromInsert вылетает - вы присваиваете массив строк свойству, которое является строкой).
Вместо этого вам нужно создать 7 объектов TrainingDay, по одному на каждый день недели. Поскольку они не меняются, вы можете сделать это как разовую задачу, когда ваше приложение запускается впервые, или (как я делаю ниже) "лениво", когда вы пытаетесь получить их. Вам не нужно awakeFromInsert
код, но я бы порекомендовал добавить еще один атрибут к сущности, скажем, "dayIndex", который позволит вам сортировать объекты TrainingDay в логическом порядке. Ваш код может выглядеть примерно так:
// load the TrainingDays data...
let fetchRequest = NSFetchRequest(entityName: "TrainingDay")
let sort = NSSortDescriptor(key: "dayIndex", ascending: true)
fetchRequest.sortDescriptors = [sort]
daysArray = (moc!.executeFetchRequest(fetchRequest, error: nil) as? [TrainingDay])!
if daysArray.count == 0 { // nothing there
let dayEntity = NSEntityDescription.entityForName("TrainingDay", inManagedObjectContext: moc!)
let days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
for (index, name) in enumerate(days) {
let newDay = TrainingDay(entity: dayEntity!, insertIntoManagedObjectContext: moc)
newDay.day = name
newDay.dayIndex = index
daysArray.append(newDay)
}
moc.save(&error)
}
Вы могли бы положить это в viewDidLoad
или в функции, вызванной из VDL. Тогда вы можете использовать daysArray
как источник данных для вашего представления выбора
Заполнение вида выбора
отказаться от daysOfPickerView
и использовать daysArray
вместо...
//PICKER VIEW DELEGATE AND DATASOURCE METHODS
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return daysArray.count
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
let trainingDay = daysArray[row]
return trainingDay.day
}
Назначение объекта TrainingDetails правильному дню
в appendTrainingDetailsToArray
метод, вам нужно определить, какой день в настоящее время выбран в представлении выбора. Для этого вам нужно добавить переменную @IBOutlet для pickerView и подключить ее к раскадровке. Затем вы можете получить к нему доступ и установить отношения для TrainingDetails...
let row = pickerView.selectedRowInComponent(0)
let currentDay = daysArray[row]
trainingDetails.trainingDay = currentDay
Заполнение табличного представления В настоящее время вы используете три отдельных массива. Я бы использовал только один:
var detailsArray = [TrainingDetails]()
Тогда используйте свойства TrainingDetails
заполнить ячейки табличного представления, т.е.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "exerciseCell"
var cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as? UITableViewCell
if cell == nil {
cell = UITableViewCell(style: UITableViewCellStyle.Value2, reuseIdentifier: cellIdentifier)
}
let row = indexPath.row
let details = detailsArray[indexPath.row]
cell!.textLabel!.text = details.exerciseName
cell?.detailTextLabel?.text = "Sets: #\(details.setsNumber) Reps: #\(details.repsNumber)"
return cell!
}
Также измените другие методы источника данных табличного представления, чтобы использовать detailsArray.
Ваши три массива в настоящее время создаются с использованием append...
метод, но я думаю, что вы хотите, чтобы заполнить табличное представление с правильным 'TrainingDetails` для выбранного дня...
Реагирование на изменение вида сборщика
В настоящее время ваш код, кажется, создает новый TrainingDetails
каждый раз, когда меняется вид сборщика. Вместо этого просто выберите TrainingDetails для выбранного дня и перезагрузите таблицу:
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
let currentDay = daysArray[row]
let fetchRequest = NSFetchRequest(entityName: "TrainingDetails")
let predicate = NSPredicate(format: "trainingDay = %@", currentDay)
fetchRequest.predicate = predicate
let sort = NSSortDescriptor(key: "exerciseName", ascending: true)
fetchRequest.sortDescriptors = [sort]
detailsArray = (moc!.executeFetchRequest(fetchRequest, error: nil) as? [TrainingDetails])!
exerciseTableView.reloadData()
}
Дальнейшие мысли
Вы объявили NSFetchedResultsController
но не использовал его. Было бы целесообразно использовать его вместо исходного NSFetchRequest, поскольку он будет автоматически реагировать на добавление вами новых TrainingDetails и добавлять их в таблицу, а не использовать reloadData(). Но это на другой день...
Кроме того, если вы простите меня, вы немного либеральны с опциями:! а также?. Я оставил их без изменений, где я скопировал ваш код, но вы можете привести их в порядок. Аналогично с error
аргумент для контекстных операций - всегда стоит его использовать. Тем не менее, я написал вышеупомянутое, не тестируя его в XCode, так что простите меня, если я сделал некоторые ошибки в некоторых местах; надеюсь, вы можете увидеть идею.
Это не собирается компилироваться, и я, возможно, смешал Swift и C# (!), Но общая идея показана ниже...
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int
{
return trainingDays.Count;
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String!
{
return trainingDays[row].Name
}
// Variable for holding the selected day from the PickerView...
TrainingDay selectedTrainingDay;
// Set the selected TraininDay when the user choses a day from the PickerView
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)
{
selectedTrainingDay = trainingDays[row]
}
// Save the record
func Done()
{
// Create the trainingDetails
let detailsEntity = NSEntityDescription.entityForName("TrainingDetails", inManagedObjectContext: moc!)
let trainingdetails = TrainingDetails(entity: detailsEntity!, insertIntoManagedObjectContext: moc)
trainingdetails.exerciseName = exerciseName.text
trainingdetails.setsNumber = setsNumber.text!
trainingdetails.repsNumber = repsNumber.text!
trainingdetails.trainingDay = selectedTrainingDay
var error: NSError?
moc?.save(&error)
}
// Array for holding the trainingDays
Array<TrainingDay> trainingDays = new Array<TrainingDay>()
// Create Core Data objects for each training day
// Call this once only or you will end up with multiple trainingDays
// So you need to do this the first time the app is run
// You can do a fetch on startup to see if they exist, and create them
// if they don't.
// Subsequent starts you will need to do a fetch to populate the
// trainingDays array... Sorry no code for that here.
func createTrainingDays(moc:NSManagedObjectContext)
{
trainingDays.Add(createTrainingDay(moc, "TrainingDay", 0, "Sunday"));
trainingDays.Add(createTrainingDay(moc, "TrainingDay", 1, "Monday"));
trainingDays.Add(createTrainingDay(moc, "TrainingDay", 2, "Tuesday"));
trainingDays.Add(createTrainingDay(moc, "TrainingDay", 3, "Wednesday"));
trainingDays.Add(createTrainingDay(moc, "TrainingDay", 4, "Thursday"));
trainingDays.Add(createTrainingDay(moc, "TrainingDay", 5, "Friday"));
trainingDays.Add(createTrainingDay(moc, "TrainingDay", 6, "Saterday"));
moc.save()
}
// Helper Function
func createTrainingDay(moc:NSManagedObjectContext, entityName:String, sortIndex:Int, name:String) -> NSManagedObject
{
if let newManagedObject:NSManagedObject = NSEntityDescription.insertNewObjectForEntityForName(entityName, inManagedObjectContext:moc) {
newManagedObject.setValue(sortIndex, forKey:"sortIndex")
newManagedObject.setValue(name, forKey:"name")
return newManagedObject;
}
}