如何在网络线程完成之前停止UI线程?

时间:2015-07-25 05:58:52

标签: ios multithreading swift grand-central-dispatch

我正在将JSON的一些数据显示在我的AccordionView中。问题是我的View线程在我的网络线程之前完成执行。因此,我无法将从数组中获取的数据填充到我的AccordionView中。

因此它显示Array index out of range例外。我也尝试过使用reloadData方法但它没用。

我研究了这个问题,发现了GCD。我无法弄清楚如何在这个问题上使用GCD。

这是AccordionView图书馆。

    import UIKit
    import Alamofire
    import SwiftyJSON


    var CourseIdinController : String!
    var CourseDescriptionC: String!
    var ChapNameC : [String] = []
    var titleLabel : UILabel?

    class CoursePageController: UIViewController {

        @IBOutlet weak var courseDesc: UITextView!

            var CourseName : String!

            var ChapName : [String] = []

        var LessonName : [String] = []
        var myAccordionView : MKAccordionView?

        override func viewDidLoad() {
            super.viewDidLoad()
            self.title = CourseName
            self.courseDesc.text = CourseDescriptionC
            self.courseDesc.setContentOffset(CGPointZero, animated: true)

            view.bounds.size.height = 450.0
            myAccordionView = MKAccordionView(frame: CGRectMake(0, 111, CGRectGetWidth(view.bounds), CGRectGetHeight(view.bounds)));
            println(ChapNameC.count)
            myAccordionView!.delegate = self;
            myAccordionView!.dataSource = self;
            view.addSubview(myAccordionView!);
            getData()
            getlData()

        }

                func getData(){
                    Alamofire.request(.GET, "http://www.wgve.com/index.php/capp/get_chapter_by_course_id/\(CourseIdinController)")
                        .responseJSON { (_, _, data, _) in
                            let json = JSON(data!)
                            let catCount = json.count
                            for index in 0...catCount-1 {
                                let cname = json[index]["CHAPTER_NAME"].string
                                self.ChapName.append(cname!)
                                println(self.ChapName[index])
                              }
                                self.myAccordionView!.tableView?.reloadData()

                    }}

        func getlData(){
            Alamofire.request(.GET, "http://www.wgve.com/index.php/capp/get_lesson_by_course_id/\(CourseIdinController)")
                .responseJSON { (_, _, data, _) in
                    let json = JSON(data!)
                    let catCount = json.count
                    for index in 0...catCount-1 {
                        let cname = json[index]["LESSON_NAME"].string
                        self.LessonName.append(cname!)

                    }
                      self.myAccordionView!.tableView?.reloadData()
            }}


        func accordionView(accordionView: MKAccordionView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
            var cell : UITableViewCell? = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: nil)
            //cell?.imageView = UIImageView(image: UIImage(named: "lightGrayBarWithBluestripe"))

            // Background view
            var bgView : UIView? = UIView(frame: CGRectMake(0, 0, CGRectGetWidth(accordionView.bounds), 50))
            var bgImageView : UIImageView! = UIImageView(image: UIImage(named: "lightGrayBarWithBluestripe"))
            bgImageView.frame = (bgView?.bounds)!
            bgImageView.contentMode = UIViewContentMode.ScaleToFill
            bgView?.addSubview(bgImageView)
            cell?.backgroundView = bgView

            // You can assign cell.selectedBackgroundView also for selected mode

            cell?.textLabel?.text = LessonName[0]
            return cell!
        }

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



    }

    // MARK: - Implemention of MKAccordionViewDatasource method
    extension CoursePageController : MKAccordionViewDatasource {

        func numberOfSectionsInAccordionView(accordionView: MKAccordionView) -> Int {
                    println(ChapName.count)
        return ChapName.count
        }

        func accordionView(accordionView: MKAccordionView, numberOfRowsInSection section: Int) -> Int {
            println(LessonName.count)
        return LessonName.count
        }
    }

// MARK: - Implemention of MKAccordionViewDatasource method
extension CoursePageController : MKAccordionViewDatasource {

    func numberOfSectionsInAccordionView(accordionView: MKAccordionView) -> Int {
        return ChapName.count
    }

    func accordionView(accordionView: MKAccordionView, numberOfRowsInSection section: Int) -> Int {
        return LessonName.count

    }
}

// MARK: - Implemention of MKAccordionViewDelegate method
extension CoursePageController : MKAccordionViewDelegate {

    func accordionView(accordionView: MKAccordionView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return 50
    }

    func accordionView(accordionView: MKAccordionView, heightForHeaderInSection section: Int) -> CGFloat {
        return 50
    }

    func accordionView(accordionView: MKAccordionView, viewForHeaderInSection section: Int, isSectionOpen sectionOpen: Bool) -> UIView? {

        var view : UIView! = UIView(frame: CGRectMake(0, 0, CGRectGetWidth(accordionView.bounds), 50))

        // Background Image
        var bgImageView : UIImageView = UIImageView(frame: view.bounds)
        bgImageView.image = UIImage(named: ( sectionOpen ? "grayBarSelected" : "grayBar"))!
        view.addSubview(bgImageView)

        // Arrow Image
        var arrowImageView : UIImageView = UIImageView(frame: CGRectMake(15, 15, 20, 20))
        arrowImageView.image = UIImage(named: ( sectionOpen ? "close" : "open"))!
        view.addSubview(arrowImageView)

        // Title Label
         titleLabel = UILabel(frame: CGRectMake(50, 0, CGRectGetWidth(view.bounds) - 120, CGRectGetHeight(view.bounds)))

        if (ChapName.count != 0) {
            let count = ChapName.count
            for index in 0...count-1 {
                titleLabel!.text = self.ChapName[index]
            }
        }
        titleLabel!.textColor = UIColor.whiteColor()
        view.addSubview(titleLabel!)
        return view

        }
}

注意:

它显示我的错误,因为ChapName&课程名称数组为空。如果我硬编码值。它在我的控制台中打印两个数组。

可能是accordionView不支持重载方法吗? 或者我哪里错了?

更新

  1. numberOfSectionsInAccordionView会在第233行引发类似fatal error: Can't form Range with end < start的错误 请参阅此link
  2. 2. titleLabel仅返回数组中的最后一项。我不知道为什么?

2 个答案:

答案 0 :(得分:0)

关于上述代码无效的原因: 无论JSON响应如何,numberOfRowsInSection都会返回硬编码值。

关于停止UI线程: 我们有点高兴你不能这样做。 GCD可以帮助您有效地共享处理器时间,这与保持UI线程人质完全相反。如果您的网络线程以某种方式挂起,请想象后果。 UI线程会发生什么?不要这样做。

解决方案:您的UI线程足够聪明,可以处理数据缺失。即不返回部分或单元格的硬编码计数。当您收到数据时,更新您的记录(模型),向UI发送刷新消息(例如reloadData中的UITableView)。

答案 1 :(得分:0)

你应该确保你所有的json数据都成功地存储在一个数组中#accord; accordionDataArray&#34;在您尝试重新加载之前。

注意:确保数据源方法 numberOfRowsInSection numberOfSectionsInAccordionView 依赖于accordionDataArray内容(或您拥有的任何数组)来确定数据源的部分和行的数量。手风琴。

P.S。无论如何为什么要在循环中重新加载手风琴的内容? 这样做:

for index in 0...catCount-1 {
      let cname = json[index]["CHAPTER_NAME"].string
       self.ChapName.append(cname!)
       println(self.ChapName[index])
 }
 self.myAccordionView!.tableView?.reloadData()

<强>更新 为了通过ChapName&amp;当lessonName数组为空时,会要求它们显示某些值,您需要在它们出现时检查它是否正确:

if (ChapName.count != 0) {
   titleLabel!.text = self.ChapName[0] 
}

if (LessonName.count != 0){
 // do something
}

确保更新代码并进行测试。在方法中:

func accordionView(accordionView: MKAccordionView, viewForHeaderInSection section: Int, isSectionOpen sectionOpen: Bool) -> UIView? {

   [...]

   if (ChapName.count != 0) {
    titleLabel!.text = self.ChapName[0] 
   }

   [...]
}

更新2 :您正在使用的图书馆似乎不允许部分的数量为0.我建议您联系图书馆的所有者,如果可以的话#39 ; t确保节的数量至少为1。

关于你的另一个问题,titleLabel始终是数组的最后一项,你需要更改它:

        if (ChapName.count != 0) {
        let count = ChapName.count
        for index in 0...count-1 {
            titleLabel!.text = self.ChapName[index]
        }
    } 

进入这个:

titleLabel!.text = self.ChapName[section]