【问题标题】:App crashes after reopening重新打开后应用程序崩溃
【发布时间】:2016-01-24 21:58:46
【问题描述】:

基本上每次我关闭并重新打开应用程序时,它都会在我打开“历史记录”选项卡时崩溃。我很确定这是因为我如何使用 NSUserDefaults。谁能指导我完成?

我注意到的是,有时它会在重新打开后打开“历史记录”选项卡,但如果我向 Nsuserdefaults 添加一个新条目,它会崩溃,在我重新打开它后它会正常工作并显示上一个条目,或者它会删除所有内容并保留仅限新条目。

    //
    //  SecondViewController.swift
    //  Angelina
    //
    //  Created by Artiom Sobol on 1/3/16.
    //  Copyright © 2016 Artiom Sobol. All rights reserved.
    //

    import UIKit

    class History: UIViewController, UITableViewDataSource, UITableViewDelegate
    {
        // test variable
        var test: MyHistory!
        // array to store unarchived history
        var newHistory = [MyHistory]()

        //outlet for tableview

        let defaults = NSUserDefaults.standardUserDefaults()

        @IBOutlet var tableView: UITableView!

        override func viewDidLoad()
        {

            //change the background
            self.view.backgroundColor = UIColor(patternImage: UIImage(named: "newBackground.jpg")!)
            super.viewDidLoad()


            if let savedPeople = defaults.objectForKey("MyHistory") as? NSData {
                newHistory = NSKeyedUnarchiver.unarchiveObjectWithData(savedPeople) as! [MyHistory]
            }
            tableView.delegate = self
            tableView.dataSource = self
        }

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


        func tableView(tableView: UITableView,numberOfRowsInSection section: Int) -> Int
        {
            return self.newHistory.count
        }

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

        func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
        {

            let cell = tableView.dequeueReusableCellWithIdentifier("historyCell", forIndexPath: indexPath) as! historyCell
            let person = newHistory[indexPath.item]
          //  let defaults2 = NSUserDefaults.standardUserDefaults()

            print("This is count", newHistory.count)

          //  if let savedPeople = defaults.objectForKey("MyHistory") as? NSData {
        //        newHistory = //NSKeyedUnarchiver.unarchiveObjectWithData(savedPeople) as! [MyHistory]
//            }



           // cell.durationLabel.text = String(person.durationNumber)
            let (hour,minutes,seconds) = secondsToHoursMinutesSeconds(person.durationNumber)

            if(seconds < 10 && minutes < 10)
            {
                cell.durationLabel.text = "0\(hour):0\(minutes):0\(seconds)"
            }
            else if(seconds > 9 && minutes < 10)
            {
                cell.durationLabel.text = "0\(hour):0\(minutes):\(seconds)"
            }
            else if(seconds > 9 && minutes > 9)
            {
                cell.durationLabel.text = "0\(hour):\(minutes):\(seconds)"
            }
            else if(seconds < 10 && minutes > 9)
            {
                cell.durationLabel.text = "0\(hour):\(minutes):0\(seconds)"
            }


            cell.kicksLabel.text = String(person.kicksNumber)

            return cell
        }


        func secondsToHoursMinutesSeconds (seconds : Int) -> (Int, Int, Int)
        {
            return (seconds / 3600, (seconds % 3600) / 60, (seconds % 3600) % 60)
        }


    }

我想我刚刚意识到我的阵列在应用程序关闭后重新启动。这就是表崩溃的原因,因为它超出了范围..

这是我保存数组的另一个文件。

import UIKit
class Kicks: UIViewController
{
  var count = 0 as Int
    var countKicks = 0 as Int
    var kickReached = false as Bool
    var pressedOnce = true as Bool
    var timer = NSTimer()
    var test: MyHistory!
    var dateString = " "

    @IBOutlet var timerLabel: UITextField!
    @IBOutlet var kicksLabel: UITextField!

    @IBOutlet var dateDisplay: UITextField!

    @IBOutlet var kickbutton: UIButton!

    var myHistoryArray: [MyHistory] = []
    var currentMyHistory: MyHistory!

    override func viewDidLoad()
    {
        super.viewDidLoad()
        self.printTimestamp()
        // Do any additional setup after loading the view, typically from a nib.
        self.view.backgroundColor = UIColor(patternImage: UIImage(named: "background13.png")!)
    }

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

      @IBAction func kickButton()
    {

        //currentMyHistory.kicksNumber = 5
        kickbutton.setImage(UIImage(named: "gold-button-heart-icon.png"), forState: UIControlState.Normal)


        if(pressedOnce == true)
        {
            pressedOnce = false
            timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("counter"), userInfo: nil, repeats: true)
        }
        else if(kickReached == true)
        {

            //  let date = NSDate()
            //  let calendar = NSCalendar.currentCalendar()
            // let timer_total = calendar.components([ .Hour, .Minute, .Second], fromDate: date)

        }
        else if(pressedOnce == false)
        {
            countKicks++
            kicksLabel.text = "\(countKicks)"
            if(countKicks == 10)
            {
                self.printTimestamp()
                kickReached = true
                timer.invalidate()
                kickbutton.setImage(UIImage(named: "pink-button-heart-icon.png"), forState: UIControlState.Normal)
                congratsAlert()

                currentMyHistory = MyHistory(kicksNumber: countKicks, durationNumber: count)

                myHistoryArray.append(currentMyHistory)


                test = myHistoryArray[0]

                print("countof array ",  myHistoryArray.count)

                printTimestamp() // Prints "Sep 9, 2014, 4:30 AM"

                //save data
                let savedData = NSKeyedArchiver.archivedDataWithRootObject(myHistoryArray)
                let defaults = NSUserDefaults.standardUserDefaults()
                defaults.setObject(savedData, forKey: "MyHistory")
                clear()

            }
        }

    }

    func printTimestamp() {
        let timestamp = NSDateFormatter.localizedStringFromDate(NSDate(), dateStyle: .MediumStyle, timeStyle: .ShortStyle)
        print(timestamp)
        dateDisplay.text = "\(timestamp)"
    }



    // save countKicks, count, and stamp i
    func congratsAlert()
    {
        let alert = UIAlertController(title: "Congratulation", message: "Yay!!! Angelina kicked 10 times in less than 2 hours.",preferredStyle: .Alert)

        let okAction = UIAlertAction(title: "Ok",style: .Default,handler:{(action:UIAlertAction) -> Void in})
        alert.addAction(okAction)

        presentViewController(alert,animated: true,completion: nil)
    }

    func clear()
    {
        count = 0
        countKicks = 0
        kickReached = false
        pressedOnce = true
        timerLabel.text = "00:00:0\(count)"
        kicksLabel.text = "\(countKicks)"
    }

    func counter()
    {
        ++count
        let (hour,minutes,seconds) = secondsToHoursMinutesSeconds(count)

        if(seconds < 10 && minutes < 10)
        {
            timerLabel.text = "0\(hour):0\(minutes):0\(seconds)"
        }
        else if(seconds > 9 && minutes < 10)
        {
            timerLabel.text = "0\(hour):0\(minutes):\(seconds)"
        }
        else if(seconds > 9 && minutes > 9)
        {
            timerLabel.text = "0\(hour):\(minutes):\(seconds)"
        }
        else if(seconds < 10 && minutes > 9)
        {
            timerLabel.text = "0\(hour):\(minutes):0\(seconds)"
        }
    }

    func secondsToHoursMinutesSeconds (seconds : Int) -> (Int, Int, Int)
    {
        return (seconds / 3600, (seconds % 3600) / 60, (seconds % 3600) % 60)
    }

}

【问题讨论】:

  • 从输出中发布堆栈跟踪
  • 由于未捕获的异常 'NSRangeException' 导致应用程序终止,原因:'*** -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]' *** 首先抛出调用堆栈: (0x181cd5900 0x181343f80 0x181bbbac4 0x1000feb5c 0x1000fdbd8 0x100112134 0x100062840 0x1000637a4 0x186d1931c 0x186d19484 0x186d087e8 0x186d1dfb0 0x186ab308c 0x1869c3778 0x1843d2b2c 0x1843cd738 0x1843cd5f8 0x1843ccc94 0x1843cc9dc 0x1869b9c78 0x181c8c588 0x181c8a32c 0x181c8a75c 0x181bb9680 0x1830c8088 0x186a30d90 0x1000617c4 0x18175a8b8)的libc ++ abi.dylib:与类型的未捕获的异常终止NSException 跨度>
  • countof array 6 Jan 24, 2016, 14:33 countof array 1
  • 关闭应用后数组变为0
  • 为什么要更新 cellForRowAtIndexPath 方法中的 newHistory 数组?

标签: ios uitableview nsuserdefaults nskeyedarchiver nskeyedunarchiver


【解决方案1】:

上面写的很清楚:

'NSRangeException',原因:'*** -[__NSArrayI objectAtIndex:]:索引 1 超出范围 [0 .. 0]'

在您的应用启动时,仔细检查您的数组对象(如 newHistory)是否包含所有元素

好像

    func tableView(tableView: UITableView,numberOfRowsInSection section: Int) -> Int
    {
        return self.newHistory.count
    }

self.newHistory.count 不为 0 会触发cellForRowAtIndexPath,尝试在numberOfRowsInSectioncellForRowAtIndexPath 内添加两个断点,这样你就知道哪里出了问题。通常,如果没有数据,numberOfRowsInSection 会返回 0,cellForRowAtIndexPath 不会被触发。

你也可以在 Xcode BreakPoint navigator 中创建一个异常点,这样你就可以在任何异常处中断。这是您需要掌握的简单调试技巧。

【讨论】:

  • 就是问题所在,在我重新启动我的应用程序后,它会丢失所有数据。我不知道为什么
  • 您不将数据保存到磁盘吗?当您的应用程序启动时,您必须重新获取数据,然后更新您的单元格。
  • 更新了我的问题,我看到你保存并尝试重新加载,但关键是,哪个函数正在尝试读取一个空数组。必须添加异常bp或手动添加bp进行调试,应该很容易解决
  • 我明白了,谢谢! :) 我现在唯一的问题是,当我检查历史记录时,它总是向我显示 1 个条目,除非我在不添加新条目的情况下切换两次选项卡,基本上从我的理解来看,tableView 没有更新或没有足够的行?身份证:(
  • @TriscuitDelicious 不完全理解,但表格视图不会更新您的数组,除非您告诉它这样做。通常,当您更新数组时,您会调用tableView.reloadData 来更新表格视图。
猜你喜欢
  • 2014-01-30
  • 2020-12-06
  • 2013-05-30
  • 2018-10-07
  • 2012-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多