I am trying to create a background thread by using grand central dispatch and do some stuff here from alertcontroller action but it blocks the main thread. Here is my full class code, please check because I could not find what am I doing wrong? :
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
}
it is a bit of long code but any help would be quite appreciated, thanks... EDIT: the problem occurs only when I tap the ui alert controller action button "Bölümü İndir". Because all the background stuff called from that action. All other codes can be considered as context. I think it has something to do with download chapter method...
The problem is in dowloadChapter. My guess as to what is happening here is that query.findObjectsInBackgroundWithBlock calls the completion block on the main thread and then you are doing nsurlconnection calls synchronous meaning they are blocking until complete.
So, if you want it to be asynchronous, you need to dispatch to the background thread again inside the query completion. Also, you may want to consider using NSURLSession instead of NSURLConnection.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.