1. 程式人生 > >Swift學習過程問題記錄

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

=60;

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

).firstasCFCellFootView;

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

哈哈