iOS应用程序崩溃并出现EXC_BAD_ACCESS(code=1,address=0x0)错误

3

我在我的代码中遇到了一个问题,无法解决。当我运行我的应用程序时,有时会加载我的单元格,有时会立即崩溃。我认为问题出在我的cellForRowInIndexPath方法上。

我的错误出现在cellForRowInIndexPath方法的那一行:

cellDrawer.insertDescriptionLabel(cell, text: offer.title)

这是我的错误:
Thread 1: EXC_BAD_ACCESS(code=1,address=0x0)

这是我的代码:
import UIKit

class ProdutsViewController: UIViewController, UITableViewDelegate,UITableViewDataSource,UISearchResultsUpdating{

    @IBOutlet weak var tableView: UITableView!

    @IBOutlet weak var tableViewFooter: MyFooter!

    var searchResults:[Offer] = []
    var resultSearchController = UISearchController()
    var loading = false


    lazy var offers:[Offer]? = {
        print("lazy of offers\n")
        var restConnection = RestFulConnection()
        restConnection.fetchDataFromServer()
        return DataBaseChecker.getDataFromDatabase()
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        print("viewDidLoad\n")
        self.resultSearchController = ({
            let controller = UISearchController(searchResultsController: nil)
            controller.searchResultsUpdater = self
            controller.dimsBackgroundDuringPresentation = false
            controller.searchBar.sizeToFit()

            self.tableView.tableHeaderView = controller.searchBar

            return controller
        })()

        // Reload the table
        self.tableView.reloadData()

        self.tableViewFooter.hidden = true

        loadSegment()
    }

    class MyDataProvider {

        class func getInstance() -> MyDataProvider {
            print("getInstance of MyDataProvider\n")
            return MyDataProvider() //return a new instance since class vars not supported yet
        }

        func requestData(listener:([Offer]) -> ()) {
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
                //simulate delay
                sleep(1)
                print("requestData of MyDataProvider\n")
                //generate items

                var restConnection = RestFulConnection()
                restConnection.fetchDataFromServer()
                var arr = DataBaseChecker.getDataFromDatabase()

                //call listener in main thread
                dispatch_async(dispatch_get_main_queue()) {
                    listener(arr)
                }
            }
        }
    }
    func scrollViewDidScroll(scrollView: UIScrollView) {
        print("scrollViewDidScroll\n")
        let currentOffset = scrollView.contentOffset.y
        let maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height

        if (maximumOffset - currentOffset) <= 40 {
            print("IF of scrollViewDidScroll\n")
            loadSegment()
        }
    }

    func loadSegment() {
        print("loadSegment\n")
        if (!self.loading) {

            self.setLoadingState(true)
            print("IF of loadSegment\n")

            MyDataProvider.getInstance().requestData(
                {(offers:[Offer]) -> () in
                    print("block of requestData on method loadSegment\n")
                    for offer:Offer in offers {
                        print("for of loadSegment\n")
                        if(DataBaseChecker.isItNew(offer)){
                        self.offers?.append(offer)
                        }
                    }

                    self.tableView.reloadData()

                    self.setLoadingState(false)
            })
        }
    }

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

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var cell = self.tableView.dequeueReusableCellWithIdentifier("Cell",forIndexPath: indexPath) as! UITableViewCell
        print("CellForRowAtIndexPath\n")
//        var offer:Offer?
//            if (self.resultSearchController.active) {
//                offer = searchResults[indexPath.row]
//            } else {
//                offer = offers?[indexPath.row]
//            }
        if(offers != nil){
            var offer:Offer = offers![indexPath.row]
            print("IF of offers not nil, offers = \(offer.title)\n")
                var cellDrawer = CellDrawer()
                if (cell.viewWithTag(1) == nil){
                    cellDrawer.createWhiteContentInCell(cell)
                }
                cellDrawer.insertImageInCell(offer.images, cell: cell)
                cellDrawer.insertBlackContentInCell(cell)
                cellDrawer.insertDescriptionLabel(cell, text: offer.title)
                cellDrawer.insertLocalLabel(cell, text: "String Sample")
                cellDrawer.insertOldPriceLabel(cell, number: offer.oldPrice)
                //cellDrawer.insertFromPriceLabel(cell, text: "a partir de")
                cellDrawer.insertNewPriceLabel(cell,number:offer.newPrice)
        }
        return cell
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        print("NumberOfRowsInSection\n")
        if(offers != nil){
            print("IF offers not nil of NumberOfRowsInSection\n")
            if (self.resultSearchController.active) {
                print("IF2 of NumberOfRowsInSection\n")
                return searchResults.count
            } else {
                print("ELSE of NumberOfRowsInSection, offers count = \(offers!.count)\n")
                return offers!.count
            }
        }
        return 0
    }

    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        print("numberOfSectionsInTableView\n")
        if(offers != nil && offers!.count >= 1){
            print("if of numberOfSectionsInTableView\n")
                return 1
        }
        return 0
    }

    func setLoadingState(loading:Bool) {
        print("setLoadingState\n")
        self.loading = loading
        self.tableViewFooter.hidden = !loading
    }
    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        print("heightForRowAtIndexPath\n")
        return 235
    }


    func updateSearchResultsForSearchController(searchController: UISearchController)
    {
        print("updateSearchResultsForSearchController\n")
        if(offers != nil){
            print("if of updateSearchResultsForSearchController")
            searchResults.removeAll(keepCapacity: false)

            let searchPredicate = NSPredicate(format: "title CONTAINS[c] %@", searchController.searchBar.text)
            let array = NSArray(array: offers!)
            array.filteredArrayUsingPredicate(searchPredicate)
            self.searchResults = array as! [Offer]

            self.tableView.reloadData()
        }
    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
       print("prepareForSegue\n")
        if segue.identifier == "detailsSegue" {
            print("IF of prepareForSegue\n")
            let DetailTVC = segue.destinationViewController as! DetailsTVC
            if sender as! UITableView == self.resultSearchController.active {
                print("IF2 of prepareForSegue\n")
                let indexPath = self.tableView.indexPathForSelectedRow()!
                let offer = self.searchResults[indexPath.row]
                DetailTVC.offer = offer
            } else {
                print("Else of prepareForSegue\n")
                let indexPath = self.tableView.indexPathForSelectedRow()!
                let offer = self.offers![indexPath.row]
                DetailTVC.offer = offer
            }
        }
    }

}

希望有人能够提供帮助。


这是项目的git地址:https://github.com/nunesdennis/feed - Dennis Nunes
4个回答

1
如果 offer.title 不为 nil,则可能 cellDrawer 正在对一个无效的单元格执行某些操作。
在调试器中设置断点,并使用 po(打印对象)检查 offer.title 属性。
也可能是竞态条件,即在抽屉尝试加载标题时,offer 数组正在更新。

当我打印时,它返回了报价的标题,并因断点而停止。 - Dennis Nunes
尝试一下,如果let offer = offers![indexPath.row]{ // 在这里完成工作 } - some_id
我在每个方法中都有一个打印,最后两个方法是:CellForRowAtIndexPath和MyDataProvider的requestData,也许这就是你所说的... - Dennis Nunes
另外,您能否发布一些堆栈跟踪信息? - some_id
这些是最后的方法: numberOfSectionsInTableView; 如果 numberOfSectionsInTableView 存在; NumberOfRowsInSection; 如果 NumberOfRowsInSection 不为空,则提供不为空; 否则,如果 NumberOfRowsInSection 为空,则提供 count = 1; heightForRowAtIndexPath; scrollViewDidScroll; scrollViewDidScroll; heightForRowAtIndexPath; CellForRowAtIndexPath; OfferTitle; - Dennis Nunes
如果 let offer = offers![indexPath.row]{ //cell drawing code } 出现错误:条件绑定中的绑定值必须是可选类型 - Dennis Nunes

0
我曾经遇到过一个非常类似的问题,同样是这个错误。最终我找到了错误所在,原因是自定义类(MyMapView类)的@IBOutlet。在UI中使用自定义类时,需要在Interface Builder的Identity Inspector中指定该类。这解决了我的问题。

enter image description here


0
在这种情况下,我认为提供本身是nil的,当您尝试获取标题属性/ivar时,会发生崩溃。

我可以打印offer.title,但我不知道它是否会在后面变成nil。 - Dennis Nunes
我假设你正在逐步执行代码,并在以下行中看到错误:cellDrawer.insertDescriptionLabel(cell, text: offer.title); 在该行上设置断点,然后在调试器控制台中输入以下内容:'po cellDrawer'、'po cell'和'po offer'。这可能会帮助你找出哪个对象引用有问题。 - Owen Hartnett
当我尝试使用Po cellDrawer + offer时,一切都很好...但是当我尝试使用Po cellDrawer + offer.title时,标题没有打印出来...即使在第一次尝试中,offer的最后一个PO已经有了标题...当我尝试使用Po cellDrawer、Cell、Offer时...我得到了cellDrawer Fine、Cell fine和offer:<Offer: 0x7fa559dbd230> (entity: Offer; id: 0xd000000000040000 x-coredata://71D9ADA7-A4AA-445B-8654-E22CAD6C1F4E/Offer/p1 ; data: <fault>)。 - Dennis Nunes
使用相同的 Po,我再次尝试,这三个对象不是 nil/empty... -.- - Dennis Nunes
你从数组 'offers' 中获取了 'offer'。也许有一些行,而你正在超出实际行数的范围访问?确保在该部分中所说的行数与数组 'offers' 中的项目数量相等。 - Owen Hartnett
我尝试使用0代替indexPath.row,并尝试在行数和区域数中使用1,但遗憾的是没有成功。 - Dennis Nunes

0

看起来你没有为重用标识符注册类。在你的viewDidLoad函数中应该有:

tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接