standford 2015 week6
TRANSCRIPT
Standford 2015 iOS讀書會 week6
1. Multithreading 2. Table View
彼得潘
Main Queue: serial queue,⼀一次從queue取出⼀一個function執⾏行
UI相關動作⼀一定要在main queue執⾏行
Grand Central Dispatch
dispatch_async & dispatch_sync
async: return after task is added to queue
sync: return after task is done
serial & concurrent queue
https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html
demo var number1 = 0 var number2 = 0 override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. let queue = dispatch_queue_create("Queue", DISPATCH_QUEUE_SERIAL) dispatch_async(queue, { () -> Void in for i in 1...10 { self.number1++ NSThread.sleepForTimeInterval(0.1) if i == 10 { println("number1 \(self.number1) number2 \(self.number2)")
} } }) println("dispatch_async1") dispatch_async(queue, { () -> Void in for i in 1...10 { self.number2++ } }) println("dispatch_async2")
}
dispatch_async1 dispatch_async2 number1 10 number2 0
serial: FIFO
demo var number1 = 0 var number2 = 0 override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. let queue = dispatch_queue_create("Queue", DISPATCH_QUEUE_CONCURRENT) dispatch_async(queue, { () -> Void in for i in 1...10 { self.number1++ NSThread.sleepForTimeInterval(0.1) if i == 10 { println("number1 \(self.number1) number2 \(self.number2)")
} } }) println("dispatch_async1") dispatch_async(queue, { () -> Void in for i in 1...10 { self.number2++ } }) println("dispatch_async2")
}
dispatch_async1 dispatch_async2 number1 10 number2 10
demo var number1 = 0 var number2 = 0 override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. let queue = dispatch_queue_create("Queue", DISPATCH_QUEUE_SERIAL) dispatch_sync(queue, { () -> Void in for i in 1...10 { self.number1++ NSThread.sleepForTimeInterval(0.1) if i == 10 { println("number1 \(self.number1) number2 \(self.number2)")
} } }) println("dispatch_sync1") dispatch_sync(queue, { () -> Void in for i in 1...10 { self.number2++ } }) println("dispatch_sync2")
}
number1 10 number2 0dispatch_sync1dispatch_sync2
demo var number1 = 0 var number2 = 0 override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. let queue = dispatch_queue_create("Queue", DISPATCH_QUEUE_CONCURRENT) dispatch_sync(queue, { () -> Void in for i in 1...10 { self.number1++ NSThread.sleepForTimeInterval(0.1) if i == 10 { println("number1 \(self.number1) number2 \(self.number2)")
} } }) println("dispatch_sync1") dispatch_sync(queue, { () -> Void in for i in 1...10 { self.number2++ } }) println("dispatch_sync2")
}
number1 10 number2 0dispatch_sync1dispatch_sync2
不在main thread做UI會 ->
Crash ,變慢,奇怪現象
NSURLSessionfunc testDownload() { let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration()) if let url = NSURL(string: "http://res.cloudinary.com/hrscywv4p/image/upload/c_limit,f_auto,h_3000,q_80,w_1200/v1/271374/http_s3.amazonaws.com_feather-files-aviary-prod-us-east-1_f5da8ea5e_2015-03-12_723490bbf79e44a788f5cd2516fefd46_myvzle.jpg") { let request = NSURLRequest(URL: url) let task = session.downloadTaskWithRequest(request, completionHandler: { (localUrl, response, err) -> Void in let data = NSData(contentsOfURL: localUrl) let image = UIImage(data: data!) let imageView = UIImageView(image: image) self.view.addSubview(imageView) println("add image")
}) task.resume() } } 圖⽚片過⼀一段時間才出現
NSURLSession func testDownload() { let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration()) if let url = NSURL(string: "http://res.cloudinary.com/hrscywv4p/image/upload/c_limit,f_auto,h_3000,q_80,w_1200/v1/271374/http_s3.amazonaws.com_feather-files-aviary-prod-us-east-1_f5da8ea5e_2015-03-12_723490bbf79e44a788f5cd2516fefd46_myvzle.jpg") { let request = NSURLRequest(URL: url) let task = session.downloadTaskWithRequest(request, completionHandler: { (localUrl, response, err) -> Void in let data = NSData(contentsOfURL: localUrl) let image = UIImage(data: data!) dispatch_async(dispatch_get_main_queue(), { () -> Void in let imageView = UIImageView(image: image) self.view.addSubview(imageView)
}) }) task.resume() } }
建⽴立session
let session = NSURLSession.sharedSession()
let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
預設會將抓到的資料存在disk,App重新啟動還會存在
若是抓取size太⼤大的資料不會儲存在disk
建⽴立task
let task = session.dataTaskWithURL(url, completionHandler: { (data, response, err) -> Void in let image = UIImage(data: data!) dispatch_async(dispatch_get_main_queue(), { () -> Void in let imageView = UIImageView(image: image) self.view.addSubview(imageView) }) })
let task = session.downloadTaskWithRequest(request, completionHandler: { (localUrl, response, err) -> Void in let data = NSData(contentsOfURL: localUrl) let image = UIImage(data: data!) dispatch_async(dispatch_get_main_queue(), { () -> Void in let imageView = UIImageView(image: image) self.view.addSubview(imageView)
}) })
private func fetchImage() { if let url = imageURL { spinner?.startAnimating() let qos = Int(QOS_CLASS_USER_INITIATED.value) dispatch_async(dispatch_get_global_queue(qos, 0)) { () -> Void in let imageData = NSData(contentsOfURL: url) // this blocks the thread it is on dispatch_async(dispatch_get_main_queue()) { // only do something with this image // if the url we fetched is the current imageURL we want // (that might have changed while we were off fetching this one) if url == self.imageURL { // the variable "url" is capture from above if imageData != nil { // this might be a waste of time if our MVC is out of action now // which it might be if someone hit the Back button // or otherwise removed us from split view or navigation controller // while we were off fetching the image self.image = UIImage(data: imageData!) } else { self.image = nil } } } } } }
closure裡要⽤用self.image,不能只⽤用imageif url == self.imageURL : 判斷是否是⺫⽬目前要顯⽰示的圖⽚片
⽤用weak , unowned 設定self ?
table
⼀一⾏行,多⾏行輸⼊入需⽤用UITextView
收鍵盤⽅方法⼤大全
1. 在畫⾯面上加⼊入tap gesture 2. 設定return鍵觸發,經由設定Did End On Exit Event或是
delete的textFieldShouldReturn
⽅方法⼀一: resignFirstResponder ⽅方法⼆二: self.view.endEditing(true) ⽅方法三: 設定keyboardDismissMode
觸發⽅方法:
autocapitalizationType: 控制⼤大⼩小寫
observer死掉時,會⾃自動被NSNotificationCenter移除
UITableViewController搭配UITextView和UITextField獲得⾃自動scroll魔⼒力
addObserver不會增加observer的retina count
inputView: 客製化鍵盤,⽐比⽅方將picker設成鍵盤
UITableViewDataSource’s tableView(UITableView, cellForRowAtIndexPath: NSIndexPath)
UITableViewDataSource’s tableView(UITableView, titleForFooterInSection: Int)
UITableViewDataSource’s tableView(UITableView, titleForHeaderInSection: Int)
var tableFooterView: UIView
var tableHeaderView: UIView
section: 滑動表格時會固定在畫⾯面上⽅方,參考通訊錄App
UITableViewController
view就是tableView
⾃自動連結data source & delegate
如果⾃自⼰己拉的table view要⼿手動連結
static⼀一定要搭配UITableViewController
keyboard auto scroll
不限數量的內容
Dynamic Prototypes
內容⾏行數固定的表格百分之五⼗十的畫⾯面是⾏行數固定的Table
Static Cells只能搭配UITableViewController!
多出來的分隔線?
清除多出來的分隔線: tableFooterView
tableFooterViewtableHeaderView
加了header才能加footer
超級⽐比⼀一⽐比@property (nonatomic, retain) UIView *tableHeaderView;
@property (nonatomic, retain) UIView *tableFooterView;
- (UITableViewHeaderFooterView *)headerViewForSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
- (UITableViewHeaderFooterView *)footerViewForSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section;
⽅方法⼀一: UITableViewController做child controller
讓整個畫⾯面只有某部分是table的⽅方法
⽅方法⼆二: UITableView做subview
cell reuse: 圖⽚片download問題
圖⽚片完成下載時,cell已被reuse解法: : ⽅方法⼀一:在cell裡儲存url,⽐比對url確認是否顯⽰示 ⽅方法⼆二:定義cell的prepareForReuse,於其中終⽌止下載圖⽚片的動作
cell裡設定IBOutlet & IBAction
IBOutlet連結到cell的程式檔
IBAction連結到controller的程式檔
IBOutlet不能連結到controller的程式檔
在storyboard從cell拉segue時, 可以選selection 或 accessory action (對應Detail Disclosure)
//MARK: - // MARK: - Navigation
font: Headline & Body
cell點選樣式
accessory樣式
動態cell⾼高度
tableView.estimatedRowHeight = tableView.rowHeight tableView.rowHeight = UITableViewAutomaticDimension
表格的多選self.tableView.allowsMultipleSelectionDuringEditing = YES; self.tableView.editing = YES;
表格的delete
func tableView(tableView: UITableView, editingStyleForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCellEditingStyle
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath)
表格cell順序調整
func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool
func tableView(tableView: UITableView, moveRowAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath)
下拉更新的refresh
UITableViewController內建UIRefreshControl, 若是⾃自⼰己加⼊入的UITableView必須另外加上UIRefreshControl
下拉更新的refresh
@IBAction func refresh(sender: AnyObject) { self.refreshControl?.endRefreshing() }
定義下拉更新觸發的method
endRefreshing: 結束更新,表格回到正常狀態
Clear on Appearance
var clearsSelectionOnViewWillAppear: BoolUITableViewController:
設定⾴頁⾯面appear時,原本被select的cell是否取消選取,勾選表⽰示取消選取
⺫⽬目前在storyboard設定無效,預設會是取消選取, 若想改成不選取,必須另外從程式將clearsSelectionOnViewWillAppear設成false
固定某個元件, 不隨表格scroll
⽅方法⼀一: 將table加到controller的view上
⽅方法⼆二: 將UITableViewController當成child controller, 可利⽤用storyboard的Container View
固定某個元件, 不隨表格scroll
⽅方法三: 將元件加到UITableViewController的view上, 實作scrollViewDidScroll調整元件位置
override func scrollViewDidScroll(scrollView: UIScrollView) { var frame = self.blueView.frame frame.origin.y = 10 + scrollView.contentOffset.y self.blueView.frame = frame }
override func scrollViewDidScroll(scrollView: UIScrollView) { var frame = self.blueView.frame frame.origin.y = 10 + scrollView.contentOffset.y + 64 self.blueView.frame = frame }
當有透明的nav bar時
cell swipe顯⽰示多個button
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath)
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]?
http://www.codebuddies.de/2015/03/14/swipeable-cells-in-about-5-minutes-swift/