在Swift中始终追加值

时间:2018-05-23 23:14:07

标签: ios arrays swift uitableview append

编辑:只需更改代码即可显示我对Singleton建议的尝试。

所以我试图创建一个应用程序,它将从UITableView中选择一个用户并将其传递给另一个UITableView。然后,它将附加到该视图中的数组并显示为新表。这个想法是用户可以从多个列表中进行选择,并创建一个由所有选择组成的列表。

但是,我对iOS开发非常陌生,虽然我可以让它取出所选值并在新的UITableView中显示它,但它只发送一个值而不保留或追加它。意思是我永远不会在列表中显示多个添加内容。

所以,我得到的是能够选择一个单元格,让我们说"凯文史密斯",然后该值被发送到新的UITableView并显示给用户。但如果我去选择另一个值,约翰史密斯",那么只有John出现并且Kevin已经离开。

这是我的三个控制器:

第一个UITAbleView控制器

    class PlayerViewController: UITableViewController {

var resultsController: NSFetchedResultsController<Player>!
let CDSPlayer = coreDataStackPlayer()

override func viewDidLoad() {
    super.viewDidLoad()
    tableView.allowsMultipleSelection = true

    let request: NSFetchRequest<Player> = Player.fetchRequest()
    let sortDescriptor = NSSortDescriptor(key: "level", ascending: true)
    request.sortDescriptors = [sortDescriptor]
    resultsController = NSFetchedResultsController(
        fetchRequest: request,
        managedObjectContext: CDSPlayer.managedContext,
        sectionNameKeyPath: nil,
        cacheName: nil
    )

    resultsController.delegate = self

    do{
        try resultsController.performFetch()
    } catch {
        print("Perform Fetch Error: \(error)")
    }
}

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

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of rows
    return resultsController.sections?[section].numberOfObjects ?? 0
}

override func tableView(_ _tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
    let cell = tableView.dequeueReusableCell(withIdentifier: "PlayerCell", for: indexPath)
    let selectedIndexPaths = tableView.indexPathsForSelectedRows
    let rowIsSelected = selectedIndexPaths != nil && selectedIndexPaths!.contains(indexPath)
    cell.accessoryType = rowIsSelected ? .checkmark : .none
    let player = resultsController.object(at: indexPath)
    cell.textLabel?.text = player.name

    return cell
}

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    performSegue(withIdentifier: "player2form", sender: tableView.cellForRow(at: indexPath))
}

override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    let action = UIContextualAction(style:.destructive, title: "Delete"){(action, view, completion) in
        let player = self.resultsController.object(at: indexPath)
        self.resultsController.managedObjectContext.delete(player)
        do {
            try self.resultsController.managedObjectContext.save()
            self.errorMessage(message: "Player Character Deleted.");
            completion(true)
        } catch {
            print("Delete Failed: \(error)")
            self.errorMessage(message: "Failed to Delete Player Character.");
            completion(false)
        }
    }
    action.image = UIImage(named: "trash")
    action.backgroundColor = .red
    return UISwipeActionsConfiguration(actions: [action])
}

    override func prepare(for segue: UIStoryboardSegue, sender: Any?){

    if let _ = sender as? UIBarButtonItem, let vc = segue.destination as? AddPlayerViewController{
        vc.managedContext = resultsController.managedObjectContext
    }

    if let cell = sender as? UITableViewCell, let vc = segue.destination as? AddPlayerViewController{
        vc.managedContext = resultsController.managedObjectContext
        if let indexPath = tableView.indexPath(for: cell){
            let player = resultsController.object(at: indexPath)
            Service.shared.allPlayers.append(player) 
            vc.player = player
        }
    }
}

//Error Function
func errorMessage(message:String){
    let alert = UIAlertController(title: "Alert", message: message, preferredStyle:UIAlertControllerStyle.alert);
    let okAction = UIAlertAction(title:"Ok", style:UIAlertActionStyle.default, handler:nil);

    alert.addAction(okAction);
    self.present(alert, animated: true, completion:nil);
}
}

extension PlayerViewController: NSFetchedResultsControllerDelegate{

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: .automatic)
        }
    case .delete:
        if let indexPath = indexPath{
            tableView.deleteRows(at: [indexPath], with: .automatic)
        }
    case .update:
        if let indexPath = indexPath, let cell = tableView.cellForRow(at: indexPath){
            let player = resultsController.object(at: indexPath)
            cell.textLabel?.text = player.name
        }
    default:
        break
    }
}

传递数据的选择视图:

    class AddPlayerViewController: UIViewController {

var managedContext: NSManagedObjectContext!
var player: Player?
var selectedItems = [String]()

@IBOutlet weak var done_btn: UIButton!

@IBOutlet weak var playerInput: UITextField!

@IBOutlet weak var cancel_btn: UIButton!

@IBAction func add2combat(_ sender: UIButton) {
    self.performSegue(withIdentifier: "player2combat", sender: self)
}
@IBAction func done(_ sender: UIButton) {
    guard let name = playerInput.text, !name.isEmpty else {
        return //Add notice user cannot save empty items
    }

    if let player = self.player {
        player.name = name
    } else {
        //Set values from input to the cell
        let player = Player(context: managedContext)
        player.name = name
    }

    do {
        try managedContext.save()
        playerInput.resignFirstResponder()
        dismiss(animated: true)
    } catch {
        print("Error Saving Player Character: \(error)")
    }
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?){
    if segue.identifier == "player2combat" {
        let selectedItems : [String] = [playerInput.text!]
        let otherVc = segue.destination as! CombatSceneViewController
        otherVc.selectedItems = selectedItems
        print(selectedItems)
    }
}

@IBAction func cancel(_ sender: UIButton) {
    playerInput.resignFirstResponder()
    dismiss(animated: true)
}


override func viewDidLoad() {
    super.viewDidLoad()
    playerInput.becomeFirstResponder()

    if let player = player {
        playerInput.text = player.name
        playerInput.text = player.name
    }

}

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

获取数据并尝试将其附加到现有数组的UITableView。

    class CombatSceneViewController: UITableViewController{

var selectedItems =  Service.shared.allSelectedItems

override func viewDidLoad() {
    super.viewDidLoad()

    let otherVC = AddPlayerViewController()
    selectedItems.append(contentsOf: otherVC.selectedItems)

    saveData()
    loadData()
    print(selectedItems)

}


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

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return selectedItems.count
}

override func tableView(_ _tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
    let cell = tableView.dequeueReusableCell(withIdentifier: "CombatCell", for: indexPath as IndexPath)
    cell.textLabel?.text = selectedItems[indexPath.item]
    return cell
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    tableView.reloadData()
}

func saveData() {
    let data = NSMutableData()

    // 1
    let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
    let path = paths[0]
    let file = (path as NSString).appendingPathComponent("Persistent.plist")

    //2
    let archiver = NSKeyedArchiver(forWritingWith: data)
    archiver.encode(selectedItems, forKey: "Agents")
    archiver.finishEncoding()
    data.write(toFile: file, atomically: true)
}

func loadData() {
    let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
    let path = paths[0]
    let file = (path as NSString).appendingPathComponent("Persistent.plist")

    // 1
    if FileManager.default.fileExists(atPath: file) {
        if let data = NSData(contentsOfFile: file) {
            let unarchiver = NSKeyedUnarchiver(forReadingWith: data as Data)
            selectedItems = unarchiver.decodeObject(forKey: "Agents") as! [String]

            unarchiver.finishDecoding()
        }
    }
}

Singleton类:

    class Service {

static let shared = Service()

var allPlayers = [Player]()

var allSelectedItems = [String]()
}

我希望我的格式正确...这是我在这里的第一篇文章,温柔的^^;。

1 个答案:

答案 0 :(得分:0)

问题在于,当你回去时,旧玩家已经消失了,因为你没有保留它,你可以尝试为它创建一个单身

class Service {

   static let shared = Service()

   var allPlayers = [Player]()

   var allSelectedItems = [String]()

}

//保持在这里

  if let cell = sender as? UITableViewCell, let vc = segue.destination as? AddPlayerViewController{
    vc.managedContext = resultsController.managedObjectContext
    if let indexPath = tableView.indexPath(for: cell){
        let player = resultsController.object(at: indexPath)
        Service.shared.allPlayers.append(player)  // add this line
        vc.player = player
    }

 }

使用相同的逻辑来附加所选项目,当您到达final tableView时,使用

访问它们
Service.shared.allPlayers

或者

Service.shared.selectedItems

这样你就可以为所有选中的玩家提供一个持久的容器。可在应用内部随处访问的项目