NSURLConnection.sendSynchronousRequestのNSURLSessionでの代替方法(その2)

 昨日アップしたpthreadを利用したコードはほんの少しですがコードが増えるので今ひとつ美しくない。他に何かないかなとOperationQueueの土台となっている並列処理機構GCD(Grand Central Dispatch)のAPIを眺めていたらセマフォがあるのを発見。早速使ってみたところうまくいきました。pthreadに比べコードが減るのでこちらの方がオススメですね。

【Wrapperクラス(同期バージョン using GCD)】

class UCURLAccessor {
	// Private member variables
	private var doneFlag: Bool
	private var returnValue: Bool
	private let semaphore: dispatch_semaphore_t

	// Properties
	var session: NSURLSession!
	var task: NSURLSessionDataTask?
	var contentData: NSData?
	var errorMessage: String?
	
	// Initializer
	init() {
		self.session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
		self.task = nil

		self.doneFlag = false
		self.returnValue = false
		self.contentData = nil
		self.errorMessage = nil

		self.semaphore = dispatch_semaphore_create(0)
	}

	// Methods
	// Synchronous version 2 (Using GCD)
	func getContentOfURLSynchronously2(url: NSURL, referer: String? = nil) -> Bool {
		NSLog("getContentOfURLSynchronously2")
		self.contentData = nil
		self.errorMessage = nil
		
		let req = DMMakeURLRequest(url, referer: referer)
		self.task = self.session.dataTaskWithRequest(req, completionHandler: {data, resp, err in
			NSLog("Completion handler")
			if err == nil {
				let httpResp = resp as! NSHTTPURLResponse
				if httpResp.statusCode == UCDL_HTTP_STATUS_OK || httpResp.statusCode == UCDL_HTTP_STATUS_PARTIAL_CONTENT {
					self.contentData = data
					self.returnValue = true
				} else {
					self.errorMessage = self.HTTPStatusCodeToMessage(httpResp.statusCode)
					self.returnValue = false
				}
			} else {
				self.errorMessage = err!.localizedDescription
				self.returnValue = false
			}
			
			// Awake calling thread
			dispatch_semaphore_signal(self.semaphore)
		})
		self.doneFlag = false
		self.task!.resume()
		
		// Waiting for completion
		NSLog("wait...")
		dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER)
		
		NSLog("getContentOfURLSynchronously2 exit")
		return self.returnValue
	}
}

【呼び出し元】
	func test5() {
		let url = NSURL(string: "http://web.dormousesf.com/blog_photos/2016/01/19/DSCN9458HL.jpg")!
		NSLog("call getContentOfURLSynchronously2")
		let result = self.urlAccessor.getContentOfURLSynchronously2(url)
		NSLog("return from getContentOfURLSynchronously2")
		if result {
			NSLog("SUCCESS: data length=%ld", self.urlAccessor.contentData!.length)
		} else {
			NSLog("ERROR: %@", self.urlAccessor.errorMessage!)
		}
	}

【実行結果のログ】
2016-01-24 21:05:19.094 AsyncDLTest[2443:3617760] call getContentOfURLSynchronously2
2016-01-24 21:05:19.095 AsyncDLTest[2443:3617760] getContentOfURLSynchronously2
2016-01-24 21:05:19.096 AsyncDLTest[2443:3617760] wait...
2016-01-24 21:05:19.239 AsyncDLTest[2443:3617798] Completion handler
2016-01-24 21:05:19.239 AsyncDLTest[2443:3617760] getContentOfURLSynchronously2 exit
2016-01-24 21:05:19.239 AsyncDLTest[2443:3617760] return from getContentOfURLSynchronously2
2016-01-24 21:05:19.254 AsyncDLTest[2443:3617760] SUCCESS: data length=134627

サンプルプロジェクトのダウンロード

【作成・確認環境】
Mac OS X v10.11.3
Xcode v7.2


一覧に戻る