Swift學習過程問題記錄
看OC的教程,寫Swift程式碼,致醉了的人
TextField退出鍵盤:
1、sender.resignFirstResponder();
2、self.view.endEditing(true);
定義Model類時,為了方便程式設計人員之間的交流,例項化方法需要提供兩種
1、init(xxx: XXX);
2、class func modelWithXXX(xxx: XXX) ->Model{};
獲取螢幕中控制元件最大的x、y軸座標值:
1、CGRectGetMaxX(rect: CGRect)
2、CGRectGetMaxY(rect: CGRect)
NSTimer定時器,一旦呼叫invalidate()
所以需要清除記憶體,當需要再次使用定時器時,要重新例項化
使用NSTimer定時器時,需要給定時器設定執行優先順序
NSRunLoop.currentRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes);
IOS7之後設定控制元件圓角
label.layer.cornerRadius =5;
label.layer.masksToBounds =true;
設定TableView中的Cell行
1、設定tableView的行高,每行高度一致,建議使用該方法
tableView.rowHeight
2、heightForRowAtIndexPath可針對不同的行,設定對應的行高度
tableView(tableView:UITableView, heightForRowAtIndexPath indexPath:NSIndexPath) ->CGFloat { }
TableView中的Cell行,backgroundView的優先級別>backgroundColor
IOS中載入xib/nib檔案方法:
1、UINib(nibName:"CFCellFootView", bundle:nil).instantiateWithOwner(nil,
options:nil
2、NSBundle.mainBundle().loadNibNamed("CFCellFootView", owner: nil, options: nil).firstas CFCellFootView;
Swift定義代理協議:
1、使用protocol修飾符
2、繼承自NSObjectProtocol類
3、代理協議的定義,需要將對應操作的View作為引數傳遞,以便於定位
4、代理名稱的命名:控制元件類名+Delegate
5、代理方法普遍都是optional修飾
6、代理方法命名參照UITableViewDelegate:tableView + (will/did---動作) + 名稱
7、在呼叫代理時,需要判斷代理是否實現了對應的方法
計算傳遞過來的引數的所在位置的最大值
CGRectGetMaxX(rect: CGRect)
CGRectGetMaxY(rect: CGRect)
在Swift語言開發中,為了計算文字內容在螢幕中所佔據的寬度與高度,需要使用NSString型別,而不用String型別
NSString中的boundingRectWithSize()函式可以準確的計算出文字內容的寬度與高度
使用程式碼如下:
<span style="font-family:Comic Sans MS;font-size:24px;"><span style="font-family:Comic Sans MS;font-size:24px;"><span style="font-family:Comic Sans MS;font-size:24px;"><span style="font-family:Comic Sans MS;font-size:24px;"><span style="font-family:Comic Sans MS;font-size:24px;"><span style="font-family:Comic Sans MS;font-size:24px;"><span style="font-family:Comic Sans MS;font-size:24px;"><span style="font-family:Comic Sans MS;font-size:24px;"><span style="font-family:Comic Sans MS;font-size:24px;">/// CGRectGetMaxX/CGRectGetMaxY計算傳遞引數所在位置的最大值
let nameX = CGRectGetMaxX(iconView.frame) + margin;
let nameY = margin;
/// 文字內容無須換行,設定為最大值
let nameMaxSize = CGSizeMake(CGFloat(MAXFLOAT), CGFloat(MAXFLOAT));
let nameAttrs = NSDictionary(object: nameFont, forKey: NSFontAttributeName);
/**
計算文字在View中的寬度與高度
:param: <size 限制文字的最大寬度與高度
:param: options NSStringDrawingOptions.UsesLineFragmentOrigin
:param: attributes 文字內容的字型引數
:param: context nil
:returns: CGRect.size文字內容所佔據的寬度與高度
*/
let nameSize = dataSource.name.boundingRectWithSize(nameMaxSize, options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: nameAttrs, context: nil).size;</span></span></span></span></span></span></span></span></span>
UILabel設定自動換行:textView.numberOfLines =0;
列表控制元件中,如果有的Cell資料中有圖片,有的Cell中沒有圖片,需要在程式碼中設定pictureView控制元件的hidden屬性值,而不能使用removeFromSupport方法,否則在華東之後重新填充資料會導致圖片控制元件丟失
通過程式碼建立自定義Cell(Cell的高度不一致)
1、新建一個cell子類,繼承自UITableViewCell類
2、重寫init(style:UITableViewCellStyle, reuseIdentifier:String?)方法,將所有可能存在的子控制元件全部在init方法中建立,同時子控制元件需要新增到contentView中
3、針對Cell內容顯示需要提供兩個資料模型
。儲存資料的Model模型
。針對儲存資料的Model模型封裝的Frame模型。在Frame模型中包含Model模型資料,Model模型屬性的Frame資料,自定義Cell的最終高度
4、自定義Cell類只需要一個Frame模型即可,通過Frame模型可以獲取Model模型資料,不需要直接擁有Model模型資料
5、自定義Cell類通過Frame模型設定子控制元件的顯示資料與子控制元件的Frame屬性
6、Frame模型的建立與資料初始化放在Controller中,並使用懶載入的方式,達到每個Model模型資料只初始化一次,以便減少不必要的記憶體浪費
對比自定義Cell類子控制元件前後優化過程
優化之前:
1、在Controller中獲取Model模型資料集合
2、在cellForRowAtIndexPath中計算Cell子控制元件的Frame
該方式導致使用者滑動TableView時,每次載入Cell資料內容,將重複計算Cell中子控制元件的Frame,從而導致記憶體浪費
優化之後:
1、在Controller中獲取Model模型資料後,馬上計算出每個Model模型資料對應的Frame模型,Controller中封裝的資料集合為Frame模型,而不是Model模型
2、在cellForRowAtIndexPath中,直接從記憶體中獲得Frame模型,Cell只需要填充顯示子控制元件的資料內容,無須計算Frame資料
優化解析:因為使用者操作TableView時,cellforRowAtIndexPath方法將會被無限放大,頻繁在該方法中執行重複的Frame資料計算,將是一件十分浪費記憶體資源的事情,所以要將該方法中的不必要操作去除,從而達到避免記憶體浪費
以上Cell操作總結內容適用於Swift與OC
UITextField在設定背景圖片的時候,需要先取出BorderStyle屬性的邊框
程式設計過程中,分類、型別等匹配條件儘量不要使用Int型別,而使用列舉(深有感觸,可能描述不夠詳細,不過我自己能懂就OK了)
移動開發過程中的圖片拉伸技術:
1、Android中的.9圖片
2、IOS中的圖片拉伸操作:
@availability(iOS, introduced=5.0)
func resizableImageWithCapInsets(capInsets:UIEdgeInsets) ->UIImage
該方法是IOS5.0中提供的圖片拉伸技術,使用的是平鋪方式,並可以返回一個新的UIImage物件@availability(iOS, introduced=6.0)
func resizableImageWithCapInsets(capInsets:UIEdgeInsets, resizingMode:UIImageResizingMode) ->UIImage
該方法是IOS6.0中提供的圖片拉伸技術,UIImageResizingMode列舉有兩個值,Tile是平鋪的方式,同resizableImageWithCapInsets(capInsets: UIEdgeInsets) -> UIImage方法的實現效果一樣,Stretch直接拉伸。同時返回一個新的UIImage物件
func stretchableImageWithLeftCapWidth(leftCapWidth: Int, topCapHeight: Int) -> UIImage
該方法在IOS8.0中已經被廢棄了,不做過多的介紹。
開發過程中,工具方法的提取
1、編寫工具類(Java開發模式影響),多為類方法,使用class修飾方法名稱
2、Swift中,提供了使用extension的擴充套件方法,在原有系統類的基礎上進行擴充,類方法與成員方法需要根據情況區分
以上兩種方式可根據開發人員自主選擇
IOS中的通知
通知中心NSNotificationCenter
1、通知的釋出
2、通知的監聽
3、通知的移除
一個完整的通知包含3個屬性
1、name:通知的名稱
2、object:通知的釋出者
3、userInfo:通知附帶資料
代理與通知的區別
1、代理是一對第一的。一個通知釋出者對應多個接收者,同時接收者可以接收多個通知。
代理與通知的共同點
1、利用代理和通知都能完成物件之間的通訊
<span style="font-family:Comic Sans MS;font-size:24px;"><span style="font-family:Comic Sans MS;font-size:24px;"><span style="font-family:Comic Sans MS;font-size:24px;"><span style="font-family:Comic Sans MS;font-size:24px;"><span style="font-family:Comic Sans MS;font-size:24px;"><pre name="code" class="objc"> /**
* observer: 接收者
* Selector: 接收處理方法
* name: 通知名稱 當為nil時表示只要匹配object,全部接收
* object: 通知傳送者 當為nil時表示只要匹配name,全部接收
* 當name與object都為nil時,表示全部通知,全部接收
*/
center.addObserver(observer: AnyObject, selector: Selector, name: String?, object: AnyObject?)</span></span></span></span></span>
在Swift中,使用dealloc()方法,錯誤提示Cannot override 'dealloc' which has been marked unavailable,的解決方法是deinit{ },無須override和func,好坑爹
UITextFiled使用
<span style="font-family:Comic Sans MS;font-size:24px;"><span style="font-family:Comic Sans MS;font-size:24px;"><span style="font-family:Comic Sans MS;font-size:24px;"><span style="font-family:Comic Sans MS;font-size:24px;"><span style="font-family:Comic Sans MS;font-size:24px;">// 設定輸入框對應鍵盤返回鍵樣式
textInput.returnKeyType = UIReturnKeyType.Send;
// 設定輸入框的左邊距,同時需要設定leftViewMode為Always
textInput.leftView = UIView(frame: CGRectMake(0, 0, 10, 0));
textInput.leftViewMode = UITextFieldViewMode.Always;</span></span></span></span></span>
UI元素在呼叫init(reuseIdentifier:String?) {}方法時,frame/bounds都是0,在方法內獲取的控制元件寬、高值無效。解決方法,將控制元件的frame設定放在layoutSubviews()方法中。當一個控制元件的frame發生改變時,系統自動呼叫layoutSubviews()方法,所以在該方法中設定子控制元件的frame屬性
IOS中按鈕的屬性設定,內容太多,直接程式碼+註釋:
<span style="font-family:Comic Sans MS;font-size:24px;"><span style="font-family:Comic Sans MS;font-size:24px;"><span style="font-family:Comic Sans MS;font-size:24px;"><span style="font-family:Comic Sans MS;font-size:24px;">// 1、按鈕
nameView = UIButton();
// .設定按鈕背景色
nameView.setBackgroundImage(UIImage(named: "buddy_header_bg"), forState: UIControlState.Normal);
nameView.setBackgroundImage(UIImage(named: "buddy_header_bg_highlighted"), forState: UIControlState.Highlighted);
// .設定按鈕文字顏色
nameView.setTitleColor(UIColor.blackColor(), forState: UIControlState.Normal);
// .設定按鈕內容左對齊
nameView.contentHorizontalAlignment = UIControlContentHorizontalAlignment.Left;
let margin: CGFloat = 10;
// .設定按鈕整體內容的邊距
// nameView.contentEdgeInsets = UIEdgeInsets(top: 0, left: margin, bottom: 0, right: 0);
// .設定按鈕內部圖片的邊距(設定圖片右邊距,圖片與文字之間的距離沒有改變,只能再次設定按鈕內文字的邊距)
nameView.imageEdgeInsets = UIEdgeInsets(top: 0, left: margin, bottom: 0, right: 0);
// .設定按鈕內部文字的邊距
nameView.titleEdgeInsets = UIEdgeInsets(top: 0, left: margin * 2, bottom: 0, right: 0);
// .設定按鈕上的左側箭頭
var arrow = UIImage(named: "buddy_header_arrow");
nameView.setImage(arrow, forState: UIControlState.Normal);</span></span></span></span>
IOS在給View的layer設定cornerRadius屬性後,未能達到圓角效果解決方法
1、view.layer.masksToBounds = true;通過父控制元件強制所有子控制元件都按照父控制元件的尺寸,超出部分全部剪下掉
2、view.clipsToBounds = true;通過子控制元件屬性設定必須遵守父控制元件的尺寸,超出部分全部前切掉
使用UIPickerView級聯操作時,要對動態級聯的列做重新整理操作pickerView.reloadComponent(1);然後再進行選中操作
UIApplication操作:
<span style="font-family:Comic Sans MS;font-size:24px;"><span style="font-family:Comic Sans MS;font-size:24px;"><span style="font-family:Comic Sans MS;font-size:24px;"> @IBAction func onClickWithApplication() {
// 獲取Application物件
let application = UIApplication.sharedApplication();
// 設定應用圖示上的數字
// application.applicationIconBadgeNumber = 10;
// 清除應用圖示上的數字
// application.applicationIconBadgeNumber = 0;
// 設定狀態列聯網操作提示
// application.networkActivityIndicatorVisible = true;
// 隱藏狀態列聯網操作提示
// application.networkActivityIndicatorVisible = false;
// 利用Application開啟Safari瀏覽器
// application.openURL(NSURL(string: "http://www.baidu.com")!);
// 打電話
// application.openURL(NSURL(string: "tel://10086")!);
// 發簡訊
// application.openURL(NSURL(string: "sms://10086")!);
// 發郵件
// application.openURL(NSURL(string: "mailto://[email protected]")!);
// 開啟其他APP
// 設定狀態列效果,需要在info.plist中進行配置,將狀態列控制交給UIApplication
// application.statusBarHidden = true;
// application.statusBarStyle = UIStatusBarStyle.LightContent;
}
</span></span></span>
Storyboard建立方式
<span style="font-family:Comic Sans MS;font-size:24px;"><span style="font-family:Comic Sans MS;font-size:24px;"><span style="font-family:Comic Sans MS;font-size:24px;"> let storyboard = UIStoryboard(name: "Main", bundle: nil);
// 通過storyboard的instantiateInitialViewController()方法獲得啟動Controller
let mainViewController = storyboard.instantiateInitialViewController() as ViewController;
// 通過storyboard的instantiateViewControllerWithIdentifier("ViewController")方法獲得指定Identifier的Controller
let viewController = storyboard.instantiateViewControllerWithIdentifier("ViewController") as ViewController;</span></span></span>
引數中得bundle傳入nil表示預設使用NSBundle.mainBundle();使用xib建立控制器的View時,xib檔案必須要有View物件,同時還需要設定First Owner屬性
loadView()方法用來建立自定義View的內容
IOS中ViewController建立級別:loadView > Storyboard > xib
UINavigationController操作
<span style="font-family:Comic Sans MS;font-size:24px;"><span style="font-family:Comic Sans MS;font-size:24px;">// 將自己從NavigationController的棧中移除
self.navigationController?.popViewControllerAnimated(true);
// 將NavigationController移除元素,直至根元素為止
self.navigationController?.popToRootViewControllerAnimated(true);</span></span>
1月2號,今天遇到一個十分奇怪的Bug,在使用UIAlertController編寫提示框時,例項化UIAlertAction物件後,使用閉包的方式對Action的操作進行監聽,結果如果在第一行呼叫self.navigationCtroller?.popViewControllerAnimated(true);方法會提示一個十分怪異的錯誤,如果繼續在後面寫其他程式碼,這個錯誤就會消失,或者在掉該方法之前定義一個變數,錯誤也會消失,故在此做下記錄。
使用Segue進行跳轉時,Segue大致分為2大類
1、自動型:點選控制元件之後,自動執行Segue,自動完成介面跳轉。
主要執行的方法:
func prepareForSegue(segue:UIStoryboardSegue, sender:AnyObject?) :開始跳轉之前的操作
func shouldPerformSegueWithIdentifier(identifier:String?, sender:AnyObject?) ->Bool:根據返回值判斷是否進行跳轉,不過因為控制元件直接控制跳轉,並且不設定Identifier,故需要根據流程判斷是否跳轉,不推薦使用自動型
2、手動型:需要通過寫程式碼手動執行Segue,才能完成介面跳轉。同時必須設定Identifier屬性
主要呼叫的方法:
self.performSegueWithIdentifier("IdentifierWithLogin", sender:nil)
主要執行的方法:
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) :開始跳轉之前的操作
func shouldPerformSegueWithIdentifier(identifier: String?, sender: AnyObject?) -> Bool
<span style="font-family:Comic Sans MS;font-size:24px;">// 成為第一響應者
nameInput.becomeFirstResponder();
// 取消第一響應者
nameInput.resignFirstResponder();</span>
應用沙盒結構分析
1、應用程式包:包含了所有的資原始檔和可執行檔案
2、Documents:儲存應用執行時生成的需要持久化的資料,iTunes同步裝置時會備份該目錄
3、tmp:儲存應用執行時所需要的臨時資料,使用完畢後再將相應的檔案從該目錄刪除。應用沒有執行,系統也可能會清除該目錄下的檔案,iTunes不會同步備份該目錄
4、Library/Cache:儲存應用執行時生成的需要持久化的資料,iTunes同步裝置時不備份該目錄。一般存放體積大、不需要備份的非重要資料
5、Library/Preference:儲存應用的所有偏好設定,IOS的Settings應用會在該目錄中查詢應用的設定資訊。iTunes同步裝置時會備份該目錄
IOS中的資料儲存
1、儲存為plist屬性列表
func saveWithFile() {
/// 1、獲得沙盒的根路徑
let home = NSHomeDirectory() as NSString;
/// 2、獲得Documents路徑,使用NSString物件的stringByAppendingPathComponent()方法拼接路徑
let docPath = home.stringByAppendingPathComponent("Documents") as NSString;
/// 3、獲取文字檔案路徑
let filePath = docPath.stringByAppendingPathComponent("data.plist");
var dataSource = NSMutableArray();
dataSource.addObject("衣帶漸寬終不悔");
dataSource.addObject("為伊消得人憔悴");
dataSource.addObject("故國不堪回首明月中");
dataSource.addObject("人生若只如初見");
dataSource.addObject("暮然回首,那人卻在燈火闌珊處");
// 4、將資料寫入檔案中
dataSource.writeToFile(filePath, atomically: true);
println("\(filePath)");
}
func readWithFile() {
/// 1、獲得沙盒的根路徑
let home = NSHomeDirectory() as NSString;
/// 2、獲得Documents路徑,使用NSString物件的stringByAppendingPathComponent()方法拼接路徑
let docPath = home.stringByAppendingPathComponent("Documents") as NSString;
/// 3、獲取文字檔案路徑
let filePath = docPath.stringByAppendingPathComponent("data.plist");
let dataSource = NSArray(contentsOfFile: filePath);
println("\(dataSource)");
}
2、使用NSUserDefaults儲存資料
func saveWithNSUserDefaults() {
/// 1、利用NSUserDefaults儲存資料
let defaults = NSUserDefaults.standardUserDefaults();
// 2、儲存資料
defaults.setObject("衣帶漸寬終不悔", forKey: "name");
// 3、同步資料
defaults.synchronize();
}
func readWithNSUserDefaults() {
let defaults = NSUserDefaults.standardUserDefaults();
let name = defaults.objectForKey("name") as NSString;
println("\(name)");
}
3、歸檔儲存:物件需要實現NSCoding協議,歸檔對應encode,反歸檔對應decode
/**
歸檔資料
需要實現NSCoding協議
*/
func saveWithNSKeyedArchiver() {
let home = NSHomeDirectory() as NSString;
let docPath = home.stringByAppendingPathComponent("Documents") as NSString;
let filePath = docPath.stringByAppendingPathComponent("book.data");
let book = CFAddressBook(name: "Francis", call: "199");
/**
* 資料歸檔處理
*/
NSKeyedArchiver.archiveRootObject(book, toFile: filePath);
}
/**
反歸檔資料
*/
func readWithNSKeyedUnarchiver() {
let home = NSHomeDirectory() as NSString;
let docPath = home.stringByAppendingPathComponent("Documents") as NSString;
let filePath = docPath.stringByAppendingPathComponent("book.data");
let book = NSKeyedUnarchiver.unarchiveObjectWithFile(filePath) as CFAddressBook;
println("\(book.name), \(book.call)");
}
4、SQlite3
5、CoreData
哈哈