使用表视图委托时,为什么我会在索引超出范围时出现致命错误?

时间:2017-08-08 05:07:43

标签: swift delegates label tableview cell

我有两个视图控制器都包含表视图,我希望它在第一个表视图中选择一行时,当它转到下一个表视图时,单元格文本对应于他们在第一个表中选择的行表视图。想象一下设置应用程序,一旦您在行上选择,在下一个视图控制器中,您始终会看到与您在上一个表视图中选择的内容相对应的SAME单元​​格文本选项。我正在使用字典的键和值,并在行中的选择中匹配它们的索引,但是当我在运行时运行代码时,我得到一个错误,指出索引超出范围,任何人都知道为什么会发生这种情况?

首先查看控制器发生错误的代码:

 import UIKit

var trainingDict = ["Ball Handling" : ["1 Ball Stationary Drills", "1 Ball Combo Moves", "2 Ball Stationary Drills", "2 Ball Combo Moves", "2 Ball Partner Drills", "Handle Hoop Drills", "Placeholder"], "Shooting" : ["Form Shooting", "Spot Shooting", "Off The Dribble Shots", "Pull Up Jumpshots", "Catch & Shoots", "Free Throws", "Partner Shooting"], "Defense" : ["5 Star Drill", "Full Court Def. Slides", "1 v 1 Closeouts", "Gauntlet Drill", "Tennis Ball Reaction Drill", "Lane Slides", "Place Holder"], "Advanced Drills" : ["D Man Series", "Iso Series", "Double Move Series", "Gauntlet Series", "John Wall Drill", "Floater Series", "PlaceHolder"], "Vertimax Drills" : ["One Foot Jumps", "Box Jumps", "Resitance Slides", "Resistance Jumps", "Resistance Ball Handling", "Vertimax Sprints", "Slam Drill"], "Full Workouts" : ["Workout A", "Workout B", "Workout C", "Workout D", "Workout E", "Workout F", "Workout G"], "BHB Products" : ["Handle Hoops", "Handle Cubes", "Strech Bands", "Advocare", "Placeholder", "Placeholder2", "Placeholder3"]]
var gradient : CAGradientLayer!
var myIndex = 0


class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {



@IBOutlet weak var tableView: TableView!

var trainingCategories = [String]()
var arrayForKey = Array(trainingDict.values)
var selectedKey = 0




public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{

    return trainingDict.count
}




public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
    let cell = tableView.dequeueReusableCell(withIdentifier: "bell" , for: indexPath) as! ViewControllerTableViewCell

    //cell details
    cell.backgroundColor = UIColor.clear

    //gradient details
    gradient = CAGradientLayer()
    gradient.frame = tableView.bounds
    gradient.colors = [UIColor.black.cgColor, UIColor.darkGray.cgColor, UIColor.black.cgColor]
    tableView.layer.insertSublayer(gradient, at: 0)
    gradient.startPoint = CGPoint(x: 0.0, y: 0.0)
    gradient.endPoint = CGPoint(x: 1.0, y: 1.0)

    //details what the text label of cell displays
    var trainingCategories = Array(trainingDict.keys)
    trainingCategories.sort { return $0 < $1}

    cell.textLabel?.text = trainingCategories[indexPath.row]
    cell.textLabel?.textColor = UIColor.white


    print(trainingCategories.count)

    return cell
}


func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    performSegue(withIdentifier: "segue", sender: self)
    selectedKey = Int(trainingCategories[indexPath.row])!
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "segue" {
       if let secondTableView = segue.destination as? DrillsViewController {

        secondTableView.keyIndex = selectedKey

        secondTableView.arrayForKey2 = arrayForKey

                }
            }

        }




override func viewDidLoad() {
    super.viewDidLoad()
    tableView.delegate = self
    tableView.dataSource = self
    var trainingCategories = Array(trainingDict.keys)
    trainingCategories.sort { return $0 < $1}
}

为第二个视图控制器添加了代码:

  import UIKit



  class DrillsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

var arrayForKey2 = [[String]]()
var keyIndex = Int()

@IBOutlet weak var tableView: DrillsTableView!

@IBOutlet weak var drillLabel: UILabel!


public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{

    return arrayForKey2.count
}

func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}

public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell" , for: indexPath) as! DrillsTableViewCell

    //clear background color needed in order to display gradient cell
    cell.backgroundColor = UIColor.clear

    //gradient configuration
    gradient = CAGradientLayer()
    gradient.frame = tableView.bounds
    gradient.colors = [UIColor.black.cgColor, UIColor.darkGray.cgColor, UIColor.black.cgColor]
    tableView.layer.insertSublayer(gradient, at: 0)
    gradient.startPoint = CGPoint(x: 0.0, y: 0.0)
    gradient.endPoint = CGPoint(x: 1.0, y: 1.0)



    //attributes for watch/play button
    cell.playButton.layer.shadowColor = UIColor.yellow.cgColor
    cell.playButton.layer.shadowOffset = CGSize(width: 2, height: 2)
    cell.playButton.layer.shadowOpacity = 0.7
    cell.playButton.layer.shadowRadius = 1

    //details for cell label display

    cell.drillTitle.text = "\(arrayForKey2[keyIndex][indexPath.row])"


    return cell
}




override func viewDidLoad() {
    super.viewDidLoad()
    tableView.delegate = self
    tableView.dataSource = self

       }

2 个答案:

答案 0 :(得分:1)

在以下行中:

<!DOCTYPE html>
<html>
  <body>
    <!-- 1. The <iframe> (and video player) will replace this <div> tag. -->
    <div id="player"></div>

    <script>
      // 2. This code loads the IFrame Player API code asynchronously.
      var tag = document.createElement('script');

      tag.src = "https://www.youtube.com/iframe_api";
      var firstScriptTag = document.getElementsByTagName('script')[0];
      firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

      // 3. This function creates an <iframe> (and YouTube player)
      //    after the API code downloads.
      var player;
      function onYouTubeIframeAPIReady() 
      {
        player = new YT.Player('player', 
        {

              width: '100%',
              height: '800',
              videoId: 'wU4DgHHwVCc',
              startSeconds:20,
              //endSeconds:25,
              events: 
              {
                'onReady': onPlayerReady,
                'onStateChange': onPlayerStateChange
              }
        });
      }

      // 4. The API will call this function when the video player is ready.
      function onPlayerReady(event) 
      {
        event.target.seekTo(20);
        event.target.playVideo();
      }

      // 5. The API calls this function when the player's state changes.
      //    The function indicates that when playing a video (state=1),
      //    the player should play for six seconds and then stop.
      var done = false;
      function onPlayerStateChange(event) {
        if (event.data == YT.PlayerState.PLAYING && !done) {
          setTimeout(handleVideo, 5000);
          done = true;
        }
      }

      // Custom function to LOOP
      // Moves playhead back to 20 seconds
      function handleVideo() 
      {
        setTimeout(handleVideo, 5000);
        player.seekTo(20);
      }

    </script>
  </body>
</html>

您正在访问数组selectedKey = Int(trainingCategories[indexPath.row])! 的{​​{1}}元素。

首先检查indexPath.row是否包含那么多元素。

访问索引的数组超过其包含的元素会产生运行时异常trainingCategories

答案 1 :(得分:0)

值未被传递可能是因为您首先执行segue

performSegue(withIdentifier: "segue", sender: self)
    selectedKey = Int(trainingCategories[indexPath.row])!

像这样替换它

selectedKey = Int(trainingCategories[indexPath.row])!
performSegue(withIdentifier: "segue", sender: self)

请尝试让我知道如果问题仍然存在