iOS swift后台线程阻塞主线程

时间:2015-09-14 16:31:45

标签: ios multithreading swift user-interface grand-central-dispatch

我正在尝试使用grand central dispatch创建一个后台线程,并在alertcontroller操作中执行一些操作,但它阻止了主线程。这是我的完整课程代码,请检查,因为我找不到我做错了什么? :

class DisplayMangaViewController: UIViewController, UIScrollViewDelegate, UIPageViewControllerDataSource, UIToolbarDelegate {
    //variables set there
    @IBAction func actionBarButtonItem(sender: AnyObject) {
        if let popoverController = controller!.popoverPresentationController {
            popoverController.barButtonItem = sender as! UIBarButtonItem
        }
        self.presentViewController(controller!, animated: true, completion: nil)
    }
    @IBAction func actionTabBarItem(sender: AnyObject) {
        ActionSheetStringPicker.showPickerWithTitle("Sayfaya Git", rows: self.pages, initialSelection: self.pageCounter, doneBlock: {
            picker, value, index in
            var pageIndex = index.integerValue - 1
            let aimedController = self.getItemController(pageIndex)!
            let startingViewControllers: NSArray = [aimedController]
            self.pageViewController!.setViewControllers(startingViewControllers as [AnyObject], direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)
            return
            }, cancelBlock: { ActionStringCancelBlock in return }, origin: sender)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        self.navigationItem.title = self.currentChapter
        setActionSheet()
    }

    private func createPageViewController() {

        let pageController = self.storyboard!.instantiateViewControllerWithIdentifier("PageViewController") as! UIPageViewController
        pageController.dataSource = self
        if self.currentToolBar.hidden {
            pageController.view.frame = CGRect(x: 0.0, y: 0.0, width: self.view.frame.size.width, height: (self.view.frame.size.height))
        }else {
            pageController.view.frame = CGRect(x: 0.0, y: 0.0, width: self.view.frame.size.width, height: (self.view.frame.size.height - 40.0))
        }
        if imageUrlsList.count > 0 {
            let firstController = getItemController(0)!
            let startingViewControllers: NSArray = [firstController]
            pageController.setViewControllers(startingViewControllers as [AnyObject], direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)
        }
        pageViewController = pageController
        addChildViewController(pageViewController!)
        self.view.addSubview(pageViewController!.view)
        pageViewController!.didMoveToParentViewController(self)
    }

    func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {

        let itemController = viewController as! PageItemViewController

        if itemController.itemIndex > 0 {
            return getItemController(itemController.itemIndex-1)
        }

        return nil
    }

    func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {

        let itemController = viewController as! PageItemViewController

        if itemController.itemIndex+1 < pages.count {
            return getItemController(itemController.itemIndex+1)
        }

        return nil
    }

    private func getItemController(itemIndex: Int) -> PageItemViewController? {
        pageCounter = itemIndex
        setLabel()
        if itemIndex < pages.count {
            let pageItemController = self.storyboard!.instantiateViewControllerWithIdentifier("PageItemViewController") as! PageItemViewController
            pageItemController.itemIndex = itemIndex
            pageItemController.totalItem = self.pages.count
            pageItemController.strUrl1 = self.imageUrlsList[pageCounter]
            pageItemController.strUrl2 = self.imageUrlsList[(pageCounter + 1)]
            return pageItemController
        }

        return nil
    }

    func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
        return pages.count
    }

    func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {
        return 0
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()

    }

    override func viewWillAppear(animated: Bool) {
        self.view.addGestureRecognizer(tapGesture)
        self.tabBarController?.tabBar.hidden = true
    }

    override func viewDidAppear(animated: Bool) {

        if !userDefaults.boolForKey("kalınanMangaBool"){
            var viewToDisplay : UIWindow = UIApplication.sharedApplication().windows.last as! UIWindow
            self.mbProHud = MBProgressHUD.showHUDAddedTo(self.view, animated: true)
            self.mbProHud.dimBackground = true
            self.mbProHud.mode = MBProgressHUDMode.Indeterminate
            self.mbProHud.labelText = "Yükleniyor!.."
            UrlAndNameList.getPageUrlsOfChapter(currentChapter, ofManga: self.obtainedManga.name)

        }else{
            var encodedObject : NSData? = userDefaults.objectForKey("kalınanManga") as? NSData
            self.obtainedManga = NSKeyedUnarchiver.unarchiveObjectWithData(encodedObject!) as! Manga
            currentChapter = obtainedManga.chapterNu
            pageCounter = obtainedManga.pageNu
            self.pageCounter = 0
            pages = userDefaults.objectForKey("kalınanMangaPages") as! [String]
            self.imageUrlsList = userDefaults.objectForKey("kalınanMangaImageUrlsList") as! [String]
            self.navigationItem.title = obtainedManga.name + " " + currentChapter
            setLabel()
            createPageViewController()
        }

    }

    func setActionSheet(){

        controller = UIAlertController(title: "Seçenekler", message: "Ne yapmak İstersiniz?", preferredStyle: .ActionSheet)
        let actionDownload = UIAlertAction(title: "Bölümü İndir", style: UIAlertActionStyle.Default, handler: {(paramAction : UIAlertAction!) in
            var mbProHud : MBProgressHUD!
            var viewToDisplay : UIWindow = UIApplication.sharedApplication().windows.last as! UIWindow
            mbProHud = MBProgressHUD.showHUDAddedTo(viewToDisplay, animated: true)
            mbProHud.customView = UIImageView(image: UIImage(named: "37x-Checkmark.png"))
            mbProHud.mode = MBProgressHUDMode.CustomView
            mbProHud.dimBackground = true
            mbProHud.labelText = "İndirme Başlatıldı!"
            mbProHud.hide(true, afterDelay: 2)
            let qos = Int(QOS_CLASS_BACKGROUND.value)
            dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {
                var selectedChapters : [String] = [self.currentChapter]
                var mangaNameArray = [self.obtainedManga.name]
                let notification = NSNotification(name: "downloadListNotification", object: self, userInfo: ["downloadList" : selectedChapters, "mangaName" : mangaNameArray])
                self.downloadChapter(notification)
                //NSNotificationCenter.defaultCenter().postNotification(notification)
            })

        })
        controller!.addAction(actionDownload)
        let actionShare = UIAlertAction(title: "Paylaş", style: UIAlertActionStyle.Default, handler: {(paramAction : UIAlertAction!) in
            var itemsToShare : [String] = [self.obtainedManga.name, self.obtainedManga.chapterNu, self.pages[self.pageCounter], "Süperr bi mangadan süperr bi sahne! TürkİşManga Aracılığıyla..."]
            let activityViewController = UIActivityViewController(activityItems: itemsToShare, applicationActivities: nil)
            self.presentViewController(activityViewController, animated: true, completion: nil)
        })
        controller!.addAction(actionShare)
        let actionSave = UIAlertAction(title: "Favorilere Ekle", style: UIAlertActionStyle.Default, handler: {(paramAction : UIAlertAction!) in
            self.addToFav(self.obtainedManga)
        })
        controller!.addAction(actionSave)
        let actionSettings = UIAlertAction(title: "Ayarlar vs.", style: UIAlertActionStyle.Default, handler: {(paramAction : UIAlertAction!) in
            self.performSegueWithIdentifier("ayarlar", sender: self)
        })
        controller!.addAction(actionSettings)
        let actionAboutUs = UIAlertAction(title: "Biz Kimiz?", style: UIAlertActionStyle.Default, handler: {(paramAction : UIAlertAction!) in
            self.performSegueWithIdentifier("hakkımızda", sender: self)
        })
        controller!.addAction(actionAboutUs)
        let actionCancel = UIAlertAction(title: "İptal", style: UIAlertActionStyle.Default, handler: nil)
        controller!.addAction(actionCancel)
    }

    func downloadChapter(notification : NSNotification){

        let userDefaults = NSUserDefaults.standardUserDefaults()
        var filePath : String = "Turk Isi Manga"
        let qos = Int(QOS_CLASS_USER_INITIATED.value)
        //dispatch_async(dispatch_get_global_queue( qos, 0), {
            var chaptersToDownload : [String] = notification.userInfo!["downloadList"] as! [String]
            var mangaName : String = (notification.userInfo!["mangaName"] as! [String]).first!
            var downList : [DownloadingManga] = []
            for chapter in chaptersToDownload{
                var down = DownloadingManga()
                down.mangaName = mangaName
                down.chapterName = chapter
                down.progress = 0
                down.title = down.mangaName + " " + down.chapterName + "İndirilen \(down.progress)"
                downList.append(down)
            }
            var encodedObject : NSData? = userDefaults.objectForKey("currentDownloadingList") as? NSData
            var unarchivedlist = NSKeyedUnarchiver.unarchiveObjectWithData(encodedObject!) as! [DownloadingManga]
            unarchivedlist.extend(downList)
            var archivedList = NSKeyedArchiver.archivedDataWithRootObject(unarchivedlist)
            userDefaults.setObject(archivedList, forKey: "currentDownloadingList")
            userDefaults.synchronize()

            let path = NSURL.documentsFolder().URLByAppendingPathComponent("\(filePath)/covers/\(mangaName)")
            let manager = NSFileManager.defaultManager()
            if (manager.fileExistsAtPath("\(path)")) {
                println("cover image of manga named \(mangaName) has already saved")
            }else{
                var query = PFQuery(className:"MangaNamesAndUrls")
                query.whereKey("mangaName", equalTo: mangaName)
                query.findObjectsInBackgroundWithBlock {
                    (objects: [AnyObject]?, error: NSError?) -> Void in

                    if error == nil {
                        if let objects = objects as? [PFObject] {
                            var url = objects[0].objectForKey("coverImageUrl") as! String
                            if Reachability.isConnectedToNetwork(){
                                let url : NSURL? = NSURL(string: url)
                                let urlRequest = NSMutableURLRequest(URL: url!, cachePolicy: NSURLRequestCachePolicy.ReturnCacheDataElseLoad, timeoutInterval: 15.0)
                                var response: AutoreleasingUnsafeMutablePointer<NSURLResponse?> = nil
                                var error : NSErrorPointer = nil;
                                if let data = (NSURLConnection.sendSynchronousRequest(urlRequest, returningResponse: response, error: error) as NSData?) {
                                    if let img = UIImage(data: data){
                                        let filePath = NSURL.documentsFolder().URLByAppendingPathComponent("\(filePath)/covers/\(mangaName)")
                                        println("file path that cover image will be saved is \(filePath)")
                                        var fileError : NSErrorPointer = nil
                                        filePath.setResourceValue(NSNumber(bool: true), forKey: NSURLIsExcludedFromBackupKey, error: fileError)
                                        UIImagePNGRepresentation(img).writeToURL(filePath, atomically: true)
                                    }
                                }else{
                                }
                            }
                        }

                    } else {
                        println("Error: \(error!) \(error!.userInfo!)")
                    }
                }
            }

            for chapter in chaptersToDownload{
                self.createDirectory(mangaName, chapter: chapter)
                var pagesList : [String] = []
                var succeed = false
                var query = PFQuery(className: "MangaItems")
                query.whereKey("mangaName", equalTo: mangaName)
                query.whereKey("chapterName", equalTo: chapter)
                query.findObjectsInBackgroundWithBlock {
                    (objects: [AnyObject]?, error: NSError?) -> Void in
                    println(objects?.count)
                    if error == nil {
                        if let inobjects = objects as? [PFObject] {
                            for object in inobjects {
                                if let pages = object.objectForKey("pages") as? [String] {
                                    pagesList.extend(pages)
                                    println(pages)
                                }
                            }
                        }
                    }else{
                        println("Error: \(error!) \(error!.userInfo!)")
                    }
                    var counter = 0
                    for var i = 0 ; i < pagesList.count ; i++ {
                        println("attempted to download page number : \(i)")
                        if Reachability.isConnectedToNetwork(){
                            let url : NSURL? = NSURL(string: pagesList[i])
                            let urlRequest = NSMutableURLRequest(URL: url!, cachePolicy: NSURLRequestCachePolicy.ReturnCacheDataElseLoad, timeoutInterval: 15.0)
                            var response: AutoreleasingUnsafeMutablePointer<NSURLResponse?> = nil
                            var error : NSErrorPointer = nil;
                            if let data = (NSURLConnection.sendSynchronousRequest(urlRequest, returningResponse: response, error: error) as NSData?) {
                                if let img = UIImage(data: data){
                                    let filePath = NSURL.documentsFolder().URLByAppendingPathComponent("\(filePath)/\(mangaName)/\(chapter)/\(i)")
                                    UIImagePNGRepresentation(img).writeToURL(filePath, atomically: true)
                                    counter++
                                    println("downloaded page number : \(i) and counter is : \(counter)")
                                    //dispatch_async(dispatch_get_main_queue(), {
                                        var downloaded = DownloadingManga()
                                        downloaded.mangaName = mangaName
                                        downloaded.chapterName = chapter
                                        downloaded.progress = ((i + 1) * 100)/pagesList.count
                                        downloaded.title = downloaded.mangaName + " " + downloaded.chapterName + " İndirilen : \(downloaded.progress)"
                                        let notification = NSNotification(name: "downloadedNotification", object: DownloadHandler.self, userInfo: ["downloading" : downloaded])
                                        var downque = DownloadingQueueViewController()
                                        NSNotificationCenter.defaultCenter().postNotification(notification)
                                    //})
                                }
                            }else{
                            }
                        }else{
                            if userDefaults.boolForKey("isApplicationActive"){
                                //bağlantı koptu bildirilmeli ve indirmeler durdurulmalı
                                println("bağlantı koptu kontrol et")
                            }
                            //dispatch_async(dispatch_get_main_queue(), {
                                let notification = UILocalNotification()
                                notification.fireDate = NSDate(timeIntervalSinceNow: 1)
                                notification.timeZone = NSCalendar.currentCalendar().timeZone
                                notification.alertBody = "Bölüm İndirilirken Bağlantı Koptu. İndirme Tamamlanamadı! :("
                                notification.hasAction = true
                                notification.alertAction = "View"
                                notification.userInfo = [:]
                                UIApplication.sharedApplication().scheduleLocalNotification(notification)
                            //})

                            break
                        }
                        if counter == pagesList.count {
                            succeed = true
                            println("succeed = \(succeed)")
                        }else{
                            succeed = false
                            println("succeed = \(succeed)")
                        }
                    }
                    if succeed {

                        if !self.isContaining(mangaName){
                            var encodedObject : NSData? = userDefaults.objectForKey("indirilenlerList") as? NSData
                            var tempIndList = NSKeyedUnarchiver.unarchiveObjectWithData(encodedObject!) as! [Manga]
                            var manga = Manga()
                            manga.name = mangaName
                            tempIndList.insert(manga, atIndex: 0)
                            var updatedTempIndList = NSKeyedArchiver.archivedDataWithRootObject(tempIndList)
                            userDefaults.setObject(updatedTempIndList, forKey: "indirilenlerList")
                        }


                        if userDefaults.boolForKey("isApplicationActive"){
                        }else{
                            //dispatch_async(dispatch_get_main_queue(), {
                                let notification = UILocalNotification()
                                notification.fireDate = NSDate(timeIntervalSinceNow: 1)
                                notification.timeZone = NSCalendar.currentCalendar().timeZone
                                notification.alertBody = "Bölüm İndirildi :) : Belgeler/\(mangaName)/\(chapter)/! Tıkla, Hemen Oku!"
                                notification.hasAction = true
                                notification.alertAction = "View"
                                notification.applicationIconBadgeNumber++
                                notification.userInfo = [
                                    "MangaName" : mangaName,
                                    "Chapter" : chapter
                                ]
                                UIApplication.sharedApplication().scheduleLocalNotification(notification)
                            //})
                        }
                    }

                }

            }
            println("async download method has came to the end!!!!!!!!!")
        //})
    }

    func createDirectory(mangaName : String, chapter : String){
        var filePath1 : String = "Turk Isi Manga"
        // before create a new file path check it whether exist
        let filePath = NSURL.documentsFolder().URLByAppendingPathComponent("\(filePath1)/\(mangaName)/\(chapter)")
        var error:NSError?
        let fileManager = NSFileManager()
        if fileManager.createDirectoryAtURL(filePath, withIntermediateDirectories: true, attributes: nil, error: nil){
            println("succeed to create the directory")
            var fileError : NSErrorPointer = nil
            filePath.setResourceValue(NSNumber(bool: true), forKey: NSURLIsExcludedFromBackupKey, error: fileError)
        }else {
            println("failed to create the directory")
        }
    }

    func isContaining(name : String) -> Bool {
        let userDefaults = NSUserDefaults.standardUserDefaults()
        var encodedObject : NSData? = userDefaults.objectForKey("indirilenlerList") as? NSData
        var tempIndList = NSKeyedUnarchiver.unarchiveObjectWithData(encodedObject!) as! [Manga]
        var returnValue = false
        for manga in tempIndList {
            if manga.name == name {
                returnValue = true
            }
        }
        return returnValue
    }

这是一个很长的代码,但任何帮助将非常感谢,谢谢...... 编辑:只有当我点击ui警报控制器操作按钮“Bölümüİndir”时才会出现问题。因为从该动作调用的所有背景材料。所有其他代码都可以视为上下文。我认为它与下载章节方法有关...

1 个答案:

答案 0 :(得分:0)

问题在于dowloadChapter。我对这里发生的事情的猜测是,query.findObjectsInBackgroundWithBlock在主线程上调用完成块然后你正在进行nsurlconnection调用同步意味着它们阻塞直到完成。

因此,如果您希望它是异步的,则需要在查询完成内再次调度到后台线程。此外,您可能需要考虑使用NSURLSession而不是NSURLConnection。