Swift3微博項(xiàng)目筆記(第一部分)

把10月1日-10月7日期間學(xué)習(xí)Swift的筆記整理下姨丈,郁悶的是網(wǎng)上的視頻都是Swift2講課的屿衅,而我寫代碼用Swift3埃难,3和2語法有不少改變,中間出了些錯誤,記錄下涡尘。主要之前對Swift2不了解忍弛,淘寶買的視頻對于沒接觸過Swift的我來說真的很有幫助,讓我對Swift有了初步了解考抄,感謝!
https://github.com/Ossey/WeiBo
一.項(xiàng)目部署
- 1項(xiàng)目部署到oschina上:
-1.在oschina上新建一個代碼倉庫
-2.在電腦中創(chuàng)建一個文件作為本地代碼倉庫细疚,打開終端,將oschina上的代碼倉庫clone下來川梅,使用終端cd 到電腦的這個文件夾疯兼,然后敲git clone 后面跟上oschina中代碼的http路徑,就會將代碼倉庫下載到這個文件夾
-3.由于oschina上沒有swift的gitignore贫途,需要手動添加吧彪,可以到GitHub上找swift.gitignore文件,找到后打開文件丢早,把里面的內(nèi)容復(fù)制姨裸,然后通過終端創(chuàng)建.gitignore(touch . gitignore命令),打開后把剛才復(fù)制的內(nèi)容粘貼到這個新建的文件即可怨酝,建議將Pods/打開傀缩,將Pods/前面的#號刪除掉即可
-4.將新建的.gitignore添加到暫緩區(qū),命令:git add .
-5.添加到本地文件倉庫,命令:git commit -m "添加忽略文件",雙引號中寫操作的注釋
-6.添加文件到服務(wù)器中农猬,命令:git push
-7.使用Xcode創(chuàng)建項(xiàng)目扑毡,保存到剛才創(chuàng)建的本地代碼倉庫中,注意:項(xiàng)目名稱最好不要有亂七八糟的符號(比如01-盛险,!什么的)勋又,盡可能使用純英文的名稱
-8.最后在Xcode中點(diǎn)擊commit苦掘,并寫上注釋比如"初始化項(xiàng)目",再勾選push楔壤,就將該項(xiàng)目部署到oschina上了

- 2初始化項(xiàng)目
    -1.最低部署9.0
    -2.只支持豎屏
    -3.添加啟動圖片和應(yīng)用圖標(biāo)
    -4.設(shè)置Bundle name

二.搭建項(xiàng)目的主框架

方式(一): 純代碼的方式搭建主框架
-1.使用主流框架搭建
   -1.自定義tabBarController用于window的根控制器鹤啡,
   -2.創(chuàng)建各個界面對應(yīng)的控制器,并將其添加到tabBarController的子控制器數(shù)組中
   -3.由于公司提供了tabBarController的子控件的json描述文件蹲嚣,所以我們通過json文件來添加 
   -4.導(dǎo)入json文件到項(xiàng)目中递瑰,注意:導(dǎo)入json文件后,文件后面有?隙畜,說明沒有添加到git的管理之下抖部,可以右鍵文件,點(diǎn)擊scorce control 议惰,在選擇add即可慎颗,如果在Xcode中提交失敗的話,可以使用終端命令行提交試試
   -5.自定義一個方法用于通過字符串來創(chuàng)建控制器的,注意:需要在字符串前面加上【命名空間.】
   -6.在viewDidLoad方法中,解析json數(shù)據(jù)俯萎,步驟:(1)需要先獲取json文件在mainBundle中的路徑傲宜,(2)再通過路徑將獲取json文件中的內(nèi)容(這里先轉(zhuǎn)換為二進(jìn)制Data類,由于我對swift還不熟悉夫啊,所以只能先將json路徑轉(zhuǎn)換為URL函卒,然后在通過URL來轉(zhuǎn)換為Data),(3)通過序列化JSONSerialization將Data數(shù)據(jù)解析為數(shù)組撇眯。

-2.Swift處理異常的三種方式
   - 如果在調(diào)用某個方法時报嵌,該方法最后有一個throws,說明該方法會拋出異常叛本,如果一個方法會拋出異常沪蓬,那么需要對該方法進(jìn)行處理
   - 在Swift中提供了三種處理異常的方法:
    // 比如正在表達(dá)式:
    // 1.創(chuàng)建正則表達(dá)式的規(guī)則
    let pattern = "abccc"
    // 方式一:try方式,程序員手動捕捉異常
    /*
    // 2.創(chuàng)建正則表達(dá)式
    do {
        let regext = try NSRegularExpression(pattern: pattern, options: .allowCommentsAndWhitespace)
    
    } catch {
        // 系統(tǒng)提供了臨時變量error来候,通過error可以獲取到錯誤信息
        print(error)
    }
    */
    
    // 方式二:try?方式(建議使用)跷叉,系統(tǒng)幫助我們處理異常,如果該方法出現(xiàn)了異常則返回nil营搅,如果沒有異常則返回對應(yīng)的對象
    /*
    guard let regxt = try? NSRegularExpression(pattern: pattern, options: .allowCommentsAndWhitespace) else {
        return
    }
    */
    
    // 方式三:try!(不建議使用云挟、危險(xiǎn)),直接告訴系統(tǒng)該方法沒有異常,注意:如果出現(xiàn)了異常转质,那么程序會直接崩潰
    let regxt = try! NSRegularExpression(pattern: pattern, options: .allowCommentsAndWhitespace)

方式(二): 使用storyboard搭建主框架
    -1.這里需要使用到iOS9推出的storyboard reference技術(shù)
    -2.應(yīng)用程序啟動時加載main.storyboard园欣,在main.storyboard中添加子控制器,這里需要先拖入一個tabBarController休蟹,再拖入4個navigationController沸枯,讓他們成為tabBarContoller的子控制器,并給navigationController添加跟控制器為tableViewController
    -3.由于在一個storyboard中管理多個控制器比較麻煩赂弓,不好找到對應(yīng)的控制器绑榴,所以我們可以使用storyboard reference技術(shù)(選中這個控制器,點(diǎn)擊Xcode菜單-Editor-Refactor to Storyboard,就會分離出一個storyboard)盈魁,將每個導(dǎo)航控制器單獨(dú)創(chuàng)建為一個storyboard翔怎,并給導(dǎo)航控制器的跟控制器添加對應(yīng)的class來管理
tabBar上面按鈕的布局的方式
- 1.由于我們需要在tabBar中間插入一個?按鈕,所以應(yīng)該在tabBar上面預(yù)留一處空白方便添加?按鈕的
方式(一) 自定義UITabBar杨耙,通過KVC給UITabBarController設(shè)置為自定義的tabBar
方式(二) 在main.storyboard中赤套,在tabBarController中插入一個空的子控制器,注意:如果想要讓預(yù)留的地方在中間位置珊膜,需要把空白的控制器放在tabBarController的第二位容握,然后刪除這個控制器的item名稱,并且設(shè)置這個控制器的item按鈕的enable屬性為NO
-2.在storyboard中也可以設(shè)置tabBar的選中圖片车柠,這里我們通過代碼設(shè)置
   -在自定義的tabBarController中唯沮,遍歷items數(shù)組中所有的item(由于items是可選類型脖旱,所以需要強(qiáng)制解包,從storyboard中創(chuàng)建的tabBarController所以不用怕items為空的情況)介蛉,設(shè)置每個item的選中圖片萌庆,注意:調(diào)整tabBar的item的屬性需要在viewWillAppear中調(diào)整,不要在viewDidLoad方法中調(diào)整币旧,因?yàn)樵趘iewDidLoad中調(diào)整的話践险,調(diào)用viewWillAppear時,又會將tabBar的item調(diào)整為storyboard中的狀態(tài)
-3.tabBar中添加?按鈕吹菱,使用UIButton添加到tabBar中巍虫,可以在tabBarController的viewDidLoad中添加,按鈕可以使用懶加載的方式
-4.抽取封裝代碼:添加一個extension鳍刷,專門設(shè)置UI界面占遥,把設(shè)置UI界面的代碼,在extension添加相關(guān)函數(shù)输瓜,抽取在里面
-5.注意:Swift3的extension中不能訪問當(dāng)前文件非extension定義的私有屬性和方法
-6.swift中沒有分類瓦胎,用extension代替了
-7.創(chuàng)建一個swift文件,用來給UIButton做擴(kuò)展尤揣,步驟:(1)新建一個文件夾命名為Tools專門來管理搔啊,在Tools中新建一個category文件,然后按command+n新建一個swift文件北戏,這個文件名稱可以隨便命名负芋,但是盡量能看懂(比如UIButton-Extension),注意:將文件默認(rèn)的Foundtion框架換位UIKit框架,不然寫代碼沒提示哦嗜愈,然后就寫上 extension UIButton {}旧蛾,在{}中寫擴(kuò)展的函數(shù),建議寫類方法
-8.swift中類方法是以class開頭的蠕嫁,類似與OC的+開頭的方法锨天,格式: class func 函數(shù)名(參數(shù)名: 參數(shù)類型)  -> 返回值類型 { 這里面實(shí)現(xiàn)函數(shù) }
-9.我們還可以給UIButton擴(kuò)展一個便利構(gòu)造函數(shù)(初始化),以init開頭拌阴,構(gòu)造函數(shù)不需要寫返回值
-10.便利構(gòu)造函數(shù)
convenience : 便利,使用convenience修飾的構(gòu)造函數(shù)叫做便利構(gòu)造函數(shù)
 便利構(gòu)造函數(shù)通常用在對系統(tǒng)的類進(jìn)行構(gòu)造函數(shù)的擴(kuò)充時使用
 便利構(gòu)造函數(shù)的特點(diǎn)
 1.便利構(gòu)造函數(shù)通常都是寫在extension里面
 2.便利構(gòu)造函數(shù)init前面需要加載convenience
 3.在便利構(gòu)造函數(shù)中需要明確的調(diào)用self.init(),比如以下代碼
 convenience init(imageName: String, backGroundImageName: String) {
    self.init()
    setImage(UIImage(named: imageName), for: .normal)
    setImage(UIImage(named: imageName + "_highlighted"), for: .highlighted)
    setBackgroundImage(UIImage(named: backGroundImageName), for: .normal)
    setBackgroundImage(UIImage(named: backGroundImageName + "_highlighted"), for: .highlighted)
    sizeToFit()
}
-11.事件監(jiān)聽注意事項(xiàng):
     -監(jiān)聽加號按鈕的點(diǎn)擊事件奶镶,點(diǎn)擊事件調(diào)用的方法專門在tabBarController文件下寫一個extension來管理
     -事件監(jiān)聽的本質(zhì)迟赃,就是發(fā)送消息,但是發(fā)送消息是OC的特性
     -發(fā)送消息的過程:將方法包裝成@SEL --> 去類中查找方法列表 --> 根據(jù)@SEL查找imp指針(函數(shù)指針) --> 執(zhí)行函數(shù)
     -如果swift中將一個函數(shù)聲明成private厂镇,那么該函數(shù)不會添加到方法列表中纤壁,
     -如果在該函數(shù)前面加上@objc, 那么該函數(shù)依舊會被添加到方法列表中
     -如果調(diào)用的private聲明的函數(shù)不在一個class的{}大括號中或extension的{}大括號中捺信,會報(bào)錯的
【訪客視圖】的邏輯
- 當(dāng)用戶打開程序且并沒有登錄賬號時酌媒,給用戶呈現(xiàn)訪客視圖欠痴,而不是我們的主界面
- 最終方案:
 -搞一個Bool變量,判斷有沒有登錄秒咨,比如isLogin喇辽,當(dāng)isLogin = flase(沒有登錄) -->展示訪客視圖,當(dāng)isLogin = true(已經(jīng)登錄) --> 展示正常的信息
 -每個界面的訪客視圖特點(diǎn)都長得差不多
 -1.創(chuàng)建一個baseViewController類作為基類雨席,讓tabBarController的子控制器都繼承自這個類菩咨,
 -2.在這個類中定義一個變量isLogin,并賦值為flase(因?yàn)槟J(rèn)情況下肯定是沒有登錄賬號的)
 -3.定義一個私有函數(shù)初始化訪客視圖陡厘,并將訪客視圖賦值給控制器view抽米,訪客視圖需要懶加載,讓訪客視圖為一個普通的UIView
 -4.重寫loadView方法糙置,在loadView方法中用三目運(yùn)算符判斷 isLogin為ture時就調(diào)用super.loadview(),如果為flase時云茸,就調(diào)用自定義的哪個方法
  最終實(shí)現(xiàn)原理:當(dāng)用戶登錄時就會加載系統(tǒng)默認(rèn)的控制器的view,進(jìn)入登錄界面谤饭,如果用戶沒有登錄就會調(diào)用初始化訪客視圖的函數(shù)标捺,并將訪客視圖設(shè)置為控制器的view,最終當(dāng)前app中會存在4個訪客視圖网持,因?yàn)橛?個控制器繼承了baseViewController宜岛,每個控制器的view加載時都會調(diào)用loadView方法,而loadView方法中會執(zhí)行super.loadView()函數(shù)功舀,當(dāng)用戶沒有登錄時最終會調(diào)用baseViewController的loadView方法創(chuàng)建訪客視圖
 -5.自定義VisitorView(訪客視圖)萍倡,繼承自UIView,并使用XIB搭建【訪客視圖】
 -6.讓VisitorView類和XIB綁定辟汰,在VisitorView類中定義一個類方法列敲,用于創(chuàng)建一個從XIB加載的VisitorView,然后在baseViewController類中的懶加載訪客視圖時直接從VisitorView類創(chuàng)建即可
 -7.布局訪客視圖界面
     - 首頁:有一個轉(zhuǎn)盤帖汞,轉(zhuǎn)盤使用UIImageView戴而,按【command  =】可以讓圖片按原始尺寸顯示,給轉(zhuǎn)盤添加約束翩蘸,固定寬高所意,轉(zhuǎn)盤上面有一個遮罩遮住了下面小部分,這個遮罩其實(shí)是UI提供的圖片催首,這時也添加一個UIImageView扶踊,給遮住添加約束,固定高度為400(只要正好遮住轉(zhuǎn)盤底部即可)郎任,X和Y為0秧耗,這時再設(shè)置遮罩imageView的背景顏色為238、238舶治、238即可
        -當(dāng)給按鈕設(shè)置背景圖片時分井,不希望圖片拉伸處理车猬,可以在圖片管理器中選中圖片-找到slices,選中水平和垂直拉伸即可
 -8.設(shè)置訪客視圖中的內(nèi)容:由于這一設(shè)置完以后每個界面的訪客視圖長得都一樣的尺锚,所以我們需要拿到訪客視圖中的需要變化控件(拖線到VisitorView類)珠闰,該隱藏的隱藏,該顯示的顯示(這里需要設(shè)置【轉(zhuǎn)盤缩麸、logo铸磅、文字描述】)
 -9.在visitorView類中對外提供一個函數(shù),用于外界調(diào)用時設(shè)置訪客視圖的控件的屬性杭朱,方法中直接拿到參數(shù)賦值給控件阅仔,并且函數(shù)里面設(shè)置轉(zhuǎn)盤的hidden為ture(意思是只要外界調(diào)用這個方法,就讓轉(zhuǎn)盤隱藏)弧械,因?yàn)橹挥衕ome界面的訪客視圖有【轉(zhuǎn)盤】八酒,可以不調(diào)用這個方法
 -10.這樣設(shè)置后會產(chǎn)生幾個問題
     -(1)由于在xib中給log設(shè)置了寬和高的約束,導(dǎo)致其他界面設(shè)置的log圖片大小不一樣時會造成圖片顯示不全
      解決方法:給UIImageview的contenMode設(shè)置為Center(居中顯示刃唐,并且按照圖片原來的寬高比顯示)
     -(2)文字描述控件:換行時文字居中顯示
     解決方法:設(shè)置文字居中顯示
 -11.讓轉(zhuǎn)盤旋轉(zhuǎn)起來:給轉(zhuǎn)盤對應(yīng)的UIImageView控件做旋轉(zhuǎn)動畫
    -(1)定義一個函數(shù)來做轉(zhuǎn)盤動畫旋轉(zhuǎn)羞迷,旋轉(zhuǎn)是一直在轉(zhuǎn),并不會停下來
    -(2)創(chuàng)建CABasicAnimation基本動畫画饥,添加到轉(zhuǎn)盤的layer上
    -(3)產(chǎn)生問題:當(dāng)退到后臺衔瓮、或轉(zhuǎn)盤所在的view消失后,在進(jìn)入轉(zhuǎn)盤所在的view抖甘,動畫會結(jié)束且不轉(zhuǎn)
    -(4)解決方法:核心動畫都存在這種問題热鞍,這是因?yàn)閯赢嫿Y(jié)束后或view消失后,系統(tǒng)會幫我們剔除動畫衔彻,我們可以設(shè)置移除核心動畫即可
【導(dǎo)航條】及【導(dǎo)航按鈕的】設(shè)置
 -.在父類BaseViewController方法中設(shè)置導(dǎo)航條上的按鈕
  -1.注冊和登錄按鈕
  -2.在父類BaseViewController中添加extension薇宠,用于寫事件監(jiān)聽的各種方法的
  -3.設(shè)置導(dǎo)航條上所有按鈕的顏色為橙色,由于新浪所有的都是橙色艰额,可以在appDelegate類中澄港,設(shè)置UINavigationBar的全局顏色為橙色
  -4.每個訪客視圖上的注冊和登錄按鈕,也需要添加點(diǎn)擊事件柄沮,由于直接脫線監(jiān)聽方法到訪客視圖的VisitorView類中回梧,不方便出來點(diǎn)擊事件,所以我們可以將【注冊】和【登錄】按鈕拖線屬性到VisitorView類中祖搓,那么在manViewController中可以拿到這兩個屬性狱意,給其添加點(diǎn)擊事件,這樣可以讓代碼更簡潔棕硫,而且在這里我們可以直接調(diào)用導(dǎo)航條上注冊和登錄按鈕的監(jiān)聽事件防范
  -5.點(diǎn)擊導(dǎo)航條上的BarbuttonItem時髓涯,會自動切換為選中狀態(tài)袒啼,那么這些item是需要設(shè)置UIBarButtonItem的CustonView的哈扮,設(shè)置CustonView為UIButton即可
  -6.導(dǎo)航條的標(biāo)題應(yīng)該設(shè)置titleView
      -(1)在每個子類里面設(shè)置導(dǎo)航BarButtonItem的屬性纬纪,但是需要現(xiàn)在判斷【當(dāng)沒有登錄時,直接返回】滑肉,因?yàn)闆]有登錄就會加載【訪客視圖】包各,所以沒有必要設(shè)置
  -7.設(shè)置導(dǎo)航的titleView為UIButton,創(chuàng)建UIButton最好使用懶加載的方式靶庙,注意:titleView上按鈕有兩個狀態(tài)下的圖片(是箭頭)问畅,默認(rèn)情況下箭頭朝下,點(diǎn)擊時箭頭朝上(設(shè)置按鈕為選中狀態(tài) )六荒,設(shè)置完成后按鈕的【圖片在左邊】【文字在右邊】了护姆,我們需要的是文字在左邊,圖片在右邊
   -解決方法:自定義UIButton掏击,像有些設(shè)置UIButton固定屬性的可以寫在自定義的類中卵皂,重寫init(frame:)函數(shù),
   -注意:(1)必須要調(diào)用super.init(frame: frame)砚亭,(2)swift中規(guī)定:重寫控件的init(frame)函數(shù)或init()函數(shù)灯变,必須重寫init?(coder aDecoder)函數(shù)(這個函數(shù)中可以什么都不實(shí)現(xiàn)),因?yàn)橐坏┲貙慽nit方法表示我在這個方法內(nèi)做了事情捅膘,加入這個控件是從xib創(chuàng)建的會調(diào)用init?(coder aDecoder)函數(shù)添祸,那么之前重寫的init中做的事情就沒有意義了,按照系統(tǒng)默認(rèn)實(shí)現(xiàn)就可以
   -切換按鈕中imageView和label的位置寻仗,重寫layoutSubviews函數(shù)刃泌,swift中可以修改對象結(jié)構(gòu)體中成員屬性的,所以可以直接拿到控件的x值進(jìn)行修改
  -8.點(diǎn)擊titleView時彈出一個小窗口(是一個控制器)愧沟,監(jiān)聽titleView上Button的點(diǎn)擊事件蔬咬,在監(jiān)聽事件的函數(shù)中彈出這個控制器
  -9.自定義彈出的這個控制器:讓其繼承自UIViewController,由于界面是固定的沐寺,可以在使用XIB描述這個控制器的view林艘,背景是一個圖片,添加imageView設(shè)置約束為上下左右0混坞,然后給imageView設(shè)置圖片狐援,此時產(chǎn)生問題:圖片拉伸嚴(yán)重
     -解決方法:設(shè)置圖片只拉伸中間的1個點(diǎn)像素,左右不需要拉伸
  -10.使用modal彈出這個自定義控制器的問題:當(dāng)modal彈出控制器后究孕,以前顯示的控制器的view會被移除(就是黑色的)啥酱,我們需要保證以前的控制器view不被移除
    -解決方法:設(shè)置要彈出的控制器的modal樣式為自定義即可(可以通過小面包工具查看是否有之前的控制器view) popoverVc.modalPresentationStyle = .custom
   -11.改變彈出控制器的尺寸,并且彈出不應(yīng)該從底部彈出厨诸,應(yīng)該從titleView底部位置向下彈出镶殷,需要自定義轉(zhuǎn)場動畫(設(shè)置轉(zhuǎn)場的代理)
   - 解決方法:
      (1)在點(diǎn)擊titleView按鈕監(jiān)聽事件的方法中,設(shè)置轉(zhuǎn)場的代理transitioningDelegate為XYHomeViewController微酬,并遵守協(xié)議(可以專門在當(dāng)前控制器中寫一個XYHomeViewController 的 extension绘趋,遵守協(xié)議颤陶,寫協(xié)議的方法)
      (2)實(shí)現(xiàn)改變彈出控制器的尺寸  目的:改變彈出view的尺寸
       func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
          // presented: 已經(jīng)彈出的控制器    XYWeiBo.XYPopoverViewController
          // presenting: nil
          // 需要自定義一個XYPresentationController類,繼承UIPresentationController類
          return XYPresentationController(presentedViewController: presented, presenting: presenting)
        }
      (3)需要自定義XYPresentationController類陷遮,繼承UIPresentationController類,modal就是把要modal出來的控制器的view滓走,被添加到containerView(容器視圖)里面,所以需要在自定義的類中重寫containerViewWillLayoutSubviews方法,在這個方法中拿到從containerView中拿到彈出的控制器的view帽馋,修改彈出控制器的view的frame即可
      (4)讓彈出的containerView有灰灰的蒙版搅方,而且點(diǎn)擊背景就會disMiss,由于containerView所有的屬性及約束都是系統(tǒng)設(shè)置的所以最好不要去修改containerView的屬性绽族,這樣可能會出現(xiàn)問題
           解決方法:給containerView上添加一個view姨涡,設(shè)置這個view的屬性,蒙版view最好是懶加載,并給蒙版添加點(diǎn)擊手勢
           注意:給一個控件的frame賦值其他控件的bounds時吧慢,比如view.frame = imageView!.bounds绣溜,imageView此時必須要強(qiáng)制解包,不然會報(bào)錯娄蔼,因?yàn)槿绻鹖mageView?是可選類型怖喻,那么會產(chǎn)生的結(jié)果是可能為nil,swift是不能講nil賦值給CGRect結(jié)構(gòu)體的岁诉。寫上imageView!解包就可以锚沸,因?yàn)榇藭rimageView是確定類型,一定會有值的涕癣,所以不會報(bào)錯
      (5)添加蒙版到containerView上以后哗蜈,彈出的控制器view不能點(diǎn)擊了,這是因?yàn)槊砂姘褟棾龅目刂破鱲iew蓋上了坠韩,所以在添加蒙版到containerView時不能使用addSubview距潘,需要使用insertSubview,插入到containerView的第0位
      (6)當(dāng)點(diǎn)擊蒙版時只搁,讓彈出的控制器退出音比,拿到彈出的控制器調(diào)用dismiss,pressentedViewController就是被彈出的控制器氢惋,使用它dismiss即可
      (7)自定義彈出的動畫:由于現(xiàn)在使用modal彈出動畫是從底部彈出的洞翩,所以需要自定義
      (8)自定義消失動畫:自定義消失動畫和自定義彈出動畫遵守的協(xié)議都一樣,其實(shí)我們可以在home控制器搞一個變量isPresented(是否彈出)焰望,默認(rèn)設(shè)置為false骚亿,當(dāng)在設(shè)置自定義彈出動畫的方法中讓isPresented = ture,當(dāng)設(shè)置自定義消失動畫的方法中讓isPresented = false熊赖,然后專門抽取兩個方法(一個是自定義彈出動畫来屠、自定義消失動畫),然后在代理方法中使用三目運(yùn)算符【isPresented ?執(zhí)行定義彈出動畫 : 執(zhí)行自定義消失動畫】
      注意:當(dāng)做消失的動畫時俱笛,注意臨界值不要為0绣檬,不然動畫不會產(chǎn)生效果,會以下就消失了嫂粟,可以設(shè)置0.0001,只要不是0就行墨缘,動畫消失后星虹,需要把消失的view從父控件中移除
      (9)抽取所有自定義轉(zhuǎn)場的動畫到一個類中,創(chuàng)建一個名為XYPopoverAnimation的類繼承自NSObject的類镊讼,并將所有自定義轉(zhuǎn)場動畫的代碼剪切到這個類中宽涌,并修改擴(kuò)展的類名為自定義的類XYPopoverAnimation,并且在Home控制器中蝶棋,懶加載創(chuàng)建XYPopoverAnimation對象卸亮,設(shè)置為轉(zhuǎn)場動畫的代理
      (10)彈出動畫的尺寸應(yīng)該由外界決定,而不是寫死在XYPresentationController控制器中玩裙,比如Home界面中需要彈出兼贸,那這個屬性應(yīng)該由Home決定,所以可以在XYPresentationController對外提供一個屬性來設(shè)置彈出的frame(這個frame傳給XYPopoverAnimation)吃溅,然后再在XYPopoverAnimation也提供這個屬性溶诞,再將這個屬性傳遞出去(在定義這個frame時可以定義為CGRect.Zero)
      (11)目前titleView的按鈕存在一個問題:就是當(dāng)點(diǎn)擊containerView上的蒙版dismiss彈出的view時,titleView上的按鈕的箭頭不會發(fā)送變化决侈,因?yàn)辄c(diǎn)擊蒙版時并沒有執(zhí)行點(diǎn)擊按鈕中的方法螺垢,也就不會改變按鈕的選中狀態(tài)
        分析步驟:根據(jù)做的是彈出的動畫還是消失的動畫來決定按鈕的箭頭朝上還是朝下(也就是選中狀態(tài)),這樣做的話就不能在按鈕的點(diǎn)擊事件中設(shè)置按鈕的選中狀態(tài)赖歌,分析:只要XYPopoverAnimation最清楚是彈出動畫還是消失動畫枉圃,最終是要閉包和代理來傳遞都可以動畫【消失】還是【彈出】,這里使用閉包來傳遞
       解決方案:使用閉包將XYPopoverAnimation中的動畫【消失】【彈出】狀態(tài)傳遞出去庐冯,
            (1)先在XYPopoverAnimation類中定義一個閉包: var callBack : ((要接收的參數(shù) : Bool)) -> ())? ,由于閉包沒有進(jìn)行初始化賦值孽亲,需要設(shè)為可選類型
            (2)在定義【彈出】和【消失】動畫的方法中,將是否彈出傳遞給閉包
            (3)重寫init()方法展父,參數(shù)也設(shè)置為一個閉包類型(為了外界創(chuàng)建當(dāng)前類時墨林,將閉包傳遞出去),然后實(shí)現(xiàn)init方法時犯祠,將閉包參數(shù)賦值給當(dāng)前類中定義的閉包
            (4)在Home控制器創(chuàng)建XYPopoverAnimation對象時旭等,將閉包賦值給按鈕的選中狀態(tài)即可
             (5)循環(huán)引用問題解決
      注意:
           (1)如果自定義了一個構(gòu)造函數(shù),但是沒有對默認(rèn)的構(gòu)造函數(shù)init()進(jìn)行重寫衡载,那么自定義的構(gòu)造函數(shù)會覆蓋默認(rèn)的構(gòu)造函數(shù)
            (2)在閉包中如果使用當(dāng)前對象的屬性或調(diào)用方法搔耕,需要加self,目前有兩個地方需要加self,一是當(dāng)在函數(shù)中出現(xiàn)歧義的時候弃榨,二是在閉包中如果使用當(dāng)前對象的屬性或調(diào)用方法
             (3)強(qiáng)制解包一般是在等號右邊才需要強(qiáng)制解包菩收,因?yàn)楫?dāng)?shù)忍栍疫厼閚il時,左邊的屬性可能會無法接受nil鲸睛,左邊不需要強(qiáng)制解包
集成cocoaPods
      - cd到項(xiàng)目所在文件夾娜饵,使用git init命令創(chuàng)建Podfile
      - 建議使用Xcode打開Podfile,不建議使用文本編輯器打開官辈,容易出現(xiàn)符合類似的錯誤
      - 注意:swift只支持動態(tài)庫箱舞,不再支持靜態(tài)庫,添加完框架后拳亿,如果要使用框架需要導(dǎo)入框架(比如import SDWebImage),因?yàn)閏ocoaPods導(dǎo)入的框架和項(xiàng)目文件不在同一個命名空間(也就是包)中晴股,所以需要導(dǎo)入框架頭文件
AFNetworking單例封裝
- 在公司真實(shí)開發(fā)中一般不會直接使用AFNetworking,而是在使用之前會對這個框架進(jìn)行一層封裝(封裝為網(wǎng)絡(luò)工具類)肺魁,然后直接使用封裝好的網(wǎng)絡(luò)工具類
- 封裝方式:單獨(dú)創(chuàng)建一個小項(xiàng)目對AFN進(jìn)行封裝為工具類电湘,如果要使用的話,直接將封裝的工具類拖到項(xiàng)目就好了鹅经,這樣方便我們在小項(xiàng)目中進(jìn)行測試寂呛,建議按照這樣的封裝思路
  (1)新建一個項(xiàng)目,使用cocoaPods集成AFN
  (2)創(chuàng)建一個類繼承自AFHTTPSessionManager瘾晃,起名為XYNetworkTools,然后在工具類中導(dǎo)入import AFNetworking
  (3)將網(wǎng)絡(luò)工具類設(shè)計(jì)為單例模式:
        -定義一個靜態(tài)常量 static let shareInstance : XYNetworkTools = XYNetworkTools()
        -實(shí)現(xiàn)通過shareInstance拿到的永遠(yuǎn)只有一個實(shí)例昧谊,但是XYNetworkTools()拿到的不是單例
        -注意:swift中l(wèi)et是線程安全的,即使多線程同時訪問let修飾的常量酗捌,也會保證常量只會創(chuàng)建一次
  (4)封裝請求方法: 
        -設(shè)計(jì)方法時呢诬,看外界需要什么就添加對應(yīng)的參數(shù)
登錄功能:OAuth授權(quán)
  - 當(dāng)用戶點(diǎn)擊登錄按鈕,跳到登錄界面胖缤,用戶輸入正確的賬號和密碼尚镰,點(diǎn)擊登錄后,進(jìn)入用戶界面
  - 由于我們是模仿新浪微博哪廓,無法拿到真實(shí)賬號和密碼
  - 使用OAuth授權(quán)的方式
    - 分析:用戶沒有登錄賬號時狗唉,顯示的界面是訪客視圖,當(dāng)用戶點(diǎn)擊登錄按鈕時modal出一個登錄控制器涡真,在登錄控制器上添加一個WebView分俯,讓W(xué)ebView去加載網(wǎng)頁,這個網(wǎng)頁是新浪官方提供的哆料,讓用戶在新浪官方提供的這個網(wǎng)頁輸入賬號密碼缸剪,點(diǎn)擊登錄按鈕后,WebView會發(fā)送賬號和密碼到新浪服務(wù)器中东亦,服務(wù)器驗(yàn)證賬號密碼是否正確杏节,如果賬號或密碼錯誤,服務(wù)器會返回字段‘賬號或密碼錯誤’,如果賬號密碼正確奋渔,服務(wù)器會返回AccessToken(令牌)镊逝,以后都是拿AccessToken去服務(wù)器請求數(shù)據(jù),其實(shí)服務(wù)器在返回AccessToken之前是返回給我們code,然后我們通過code去換取AccessToken的
  - 開發(fā)步驟
  - 1.注冊成為新浪的開發(fā)者h(yuǎn)ttp://open.weibo.com
  - 2.創(chuàng)建modal出來的網(wǎng)頁嫉鲸,在Main文件中新建一個【OAuth(授權(quán))】文件夾撑蒜,將所有授權(quán)相關(guān)的都放在這個文件夾中,創(chuàng)建一個OAuthViewController類繼承自UIViewController玄渗,由于OAuthViewController中主要是一個WebView座菠,可以使用XIB搭建
  - 3.到BaseViewController類中監(jiān)聽登錄按鈕的事件中,創(chuàng)建OAuthViewController捻爷,并把其包裝為導(dǎo)航控制器(不然很難看),然后modal出來份企,
  - 4.設(shè)置OAuth控制器的導(dǎo)航條的按鈕(關(guān)閉按鈕也榄、填充按鈕、導(dǎo)航標(biāo)題)
  - 5.在XIB上添加一個WebView司志,設(shè)置約束上下左右為0甜紫,注意不要因?yàn)橛袑?dǎo)航欄有設(shè)置WebView頂部的約束為64,不需要這樣骂远,因?yàn)閃ebView本身繼承自UIScrollView囚霸,scrollView在導(dǎo)航控制器下會有頂部64的內(nèi)邊距,將WebView的背景顏色設(shè)置為白色
  - 6.先將WebView拖線到控制器激才,讓W(xué)ebView加載網(wǎng)頁
     - 拼接登錄頁面的URLString
     - 新建一個常量文件XYConstant拓型,專門用來存儲常量的,將請求的固定參數(shù)寫成常量
   -7.設(shè)置WebView的代理瘸恼,監(jiān)聽開始加載網(wǎng)頁劣挫、網(wǎng)頁加載完成、網(wǎng)頁加載失敗东帅,當(dāng)開始加載網(wǎng)頁時開啟指示器压固,加載完成后dismiss指示器,加載失敗時提示加載失敗
   -8.當(dāng)點(diǎn)擊填充時靠闭,自動將賬號和密碼填充到賬號和密碼框
       -(1).書寫js代碼(javascript) -- 注意:jave和javascript沒有任何關(guān)系
        let jsCode = "document.getElementById('userId').value='你的賬戶';document.getElementById('passwd').value='你的密碼';"
       -(2).執(zhí)行js代碼
        webView.stringByEvaluatingJavaScript(from: jsCode)
    -9.獲取授權(quán)的code帐我,需要拿到WebView加載的網(wǎng)頁,判斷網(wǎng)頁的url中是否有code=愧膀,有code=就截取出code=后面的字符串拦键,找到后不用再找了
    -10.發(fā)送POST請求獲取(使用code換取)AccessToken料饥,最前請求其他數(shù)據(jù)必須使用AccessToken宵蛀,發(fā)送網(wǎng)絡(luò)請求的參數(shù)在【微博開發(fā)者網(wǎng)站】--->【OAuth2.0授權(quán)認(rèn)證】---> 【OAuth2/access_token】里面有
    -11.創(chuàng)建模型類UserAccount耀找,用于保存服務(wù)器返回AccessToken里面的數(shù)據(jù),創(chuàng)建init()構(gòu)造方法涩惑,通過KVC將字典轉(zhuǎn)為模型
    -12.過期日期的處理
    -13.請求用戶登錄的信息,使用AccessToken請求用戶的信息
      注意:當(dāng)用戶登錄成功了围橡,將用戶的賬號信息保存革答,當(dāng)用戶重新啟動程序時先判斷有沒有這個賬號,再判斷AccessToken有沒有過期
    -14.在請求完用戶信息后莲镣,將UserAccount模型對象保存到沙盒的Document文件中福稳,采用歸檔、解檔的方法NSKeyedArchiver類瑞侮,注意:使用NSKeyedArchiver的圆,必須讓需要?dú)w檔或解檔的類遵守NSCoding協(xié)議,重寫解檔和歸檔方法
    -15.判斷isLogin是true還是false半火,不應(yīng)該是寫死的越妈,應(yīng)該將UserAccount解檔后來判斷,同時判斷UserAccount解檔后是否有值和AccessToken是否過期
    -16.封裝一個UserAccountViewModal視圖模型類钮糖,專門用來從沙盒中讀寫的功能用戶信息梅掠,因?yàn)樵趌oadView方法中寫太多的代碼不好,注意:如果這個不需要使用KVC的方法店归,可以讓這個類誰都不要繼承阎抒,這樣更輕量級。
       (1)類中重寫init()方法消痛,這樣當(dāng)別的對象使用這個類的時候且叁,創(chuàng)建出來就有從沙盒中讀寫的功能,在init方法中讀取用戶信息
       (2)將沙盒路徑定義為計(jì)算屬性
       (3)為了保證從沙盒中讀取的UserAccount類對象不會銷毀掉,這里定義一個成員變量秩伞,將沙盒中讀取的對象賦值給這個成員變量
       (4)定義isLogin計(jì)算屬性逞带,返回值為Bool,先判斷從沙盒中取出UserAccount類對象是否為nil纱新,如果為nil直接返回false掰担,再判斷有沒有過期日期,如果沒有直接返回fasle怒炸,最后判斷日期有沒有過期
登錄成功后進(jìn)入歡迎界面
- 布局歡迎界面
  - 1.創(chuàng)建歡迎控制器带饱,繼承自UIViewController,使用XIB描述控制器view(如何選擇XIB和storyboad阅羹,當(dāng)需要描述多個界面且界面直接有業(yè)務(wù)邏輯時使用storyboard勺疼,如果只描述一個頁面使用xib)
   -注意:swift中如果方法中有枚舉值不想傳,可以直接寫[]中括號捏鱼,如果傳多個值执庐,可以[]中寫
  - 2.布局完XIB后,給歡迎界面做動畫导梆,動畫主要是讓用戶頭像從底部跳到頂部,并且讓【歡迎回來】文本跟隨跳動轨淌,其實(shí)設(shè)置頭像距離底部的約束迂烁,在設(shè)置label距離頭像底部的約束,最后改變頭像約束值即可
- #顯示歡迎界面及邏輯
- 當(dāng)用戶登錄成功递鹉,保存完用戶數(shù)據(jù)到沙盒后顯示歡迎界面
  - 1.顯示歡迎界面之前盟步,退出之前的控制器OAuth授權(quán)界面,注意dismiss時不要有動畫
  - 2.退出OAuth界面后躏结,再顯示歡迎界面却盘,將歡迎界面設(shè)置窗口的跟控制器
      注意:這里需要將account對象賦值給XYUserAccountViewModel中的account,因?yàn)榇藭rXYUserAccountViewModel中的account為nil媳拴,XYUserAccountViewModel是單例對象黄橘,只會創(chuàng)建一次,第一次創(chuàng)建時去沙盒中沒有找到用戶信息的pllist屈溉,單例第二次不會被創(chuàng)建塞关,也就不會執(zhí)行去沙盒中解檔了
  - 3.歡迎界面動畫執(zhí)行完畢后,切換到主界面子巾,設(shè)置窗口的根控制器為MainViewcontroller帆赢,注意: MainViewcontroller是從storyboard中搭建的,需要通過storyboard加載
  - 4.設(shè)置用戶每次進(jìn)入程序時先加載歡迎界面砰左,歡迎界面動畫結(jié)束后再加載主界面匿醒,所以需要在Appdelegate中設(shè)置窗口的根控制器
   - 最佳方法:在Appdelegate中聲明一個defaultViewController計(jì)算屬性场航,拿到XYUserAccountViewModel中的isLogin屬性缠导,使用三目運(yùn)算符判斷,當(dāng)用戶登錄后加載歡迎界面溉痢,沒登錄就加載主界面(主界面是從storyboard中搭建的tabBarController僻造,主界面在沒登錄時會顯示訪客視圖)
   - 未解決的問題:歡迎界面中修改頭像底部與控制器view底部的約束,更新約束后孩饼,控制器view也跟隨做運(yùn)動做動畫
   - 已解決: 之前未解決的原因:這個項(xiàng)目我使用Xcode8寫的髓削,從XIB加載的view時,在viewDidLoad和ViewWillAppear方法中拿到的控制器view的frame是不準(zhǔn)確的镀娶,所以最終在viewDidAppear或ViewWillLayoutSubViews方法中更新子控件的約束立膛,就解決了。
請求首頁數(shù)據(jù)
- 微博開發(fā)者網(wǎng)站的文檔中有各種接口梯码,這里找到【微博接口】宝泵,找到【獲取當(dāng)前登錄用戶及其關(guān)注用戶的最新微博】接口
- 1.在網(wǎng)絡(luò)工具類中封裝請求【首頁】數(shù)據(jù)的方法,該方法中添加閉包參數(shù)轩娶,請求完成時回調(diào)此閉包參數(shù)
- 2.在Home首頁控制器中請求數(shù)據(jù)
- 3.拿到數(shù)據(jù)后儿奶,轉(zhuǎn)模型,創(chuàng)建Statues微博模型
- 4.服務(wù)器返回的某些屬性不可以直接使用鳄抒,需要對數(shù)據(jù)進(jìn)行處理闯捎,比如【source】屬性我們需要處理的話椰弊,可以定義一個變量用來接收處理后的【scurceText】屬性,再直接定義【source】為計(jì)算屬性瓤鼻,使用didSet監(jiān)聽【source】屬性值發(fā)生變化秉版,只要發(fā)送變化就處理,并把處理后的結(jié)果賦值給【scurceText】
   -注意:由于【source】是可選類型娱仔,需要使用guard判斷為nil時就返回沐飘,但是由于服務(wù)器肯還好返回空的字符串,比如“”,所以還要判斷!+ ""的情況牲迫,guard同時判斷兩個條件可以使用【where】關(guān)鍵字將兩個條件連接到一起相當(dāng)于邏輯與&&
   -微博來源處理:對字符串進(jìn)行處理(截串):(1)先獲取要截取的起始位置和要截取的字符串的長度耐朴,(2)截取字符串,并將截取后的字符串賦值給定義的屬性
   -微博創(chuàng)建時間的處理:
- 5.獲取用戶數(shù)據(jù)盹憎,創(chuàng)建XYUserItem用戶模型類筛峭,保存用戶的頭像、昵稱陪每、是否是VIP影晓、認(rèn)證等級、等相關(guān)用戶的個人信息
- 6.處理用戶個人數(shù)據(jù)
- 7.創(chuàng)建視圖模型檩禾,專門用于處理模型數(shù)據(jù)的挂签,這樣模型類就變得很簡潔
   - 步驟:在視圖模型中聲明一個statues微博模型,聲明所有要處理的模型屬性盼产,目的是處理完成后把結(jié)果賦值給這些屬性饵婆,然后自定義構(gòu)造函數(shù),給構(gòu)造函數(shù)添加一個微博模型參數(shù)戏售,方便別人創(chuàng)建時給這個模型賦值的侨核, 在構(gòu)造函數(shù)中進(jìn)行處理,需要注意的是構(gòu)造函數(shù)中如果使用對可選類型進(jìn)行解包時灌灾,不要使用guard搓译,因?yàn)槭褂胓uard時為nil就return,就沒法對下一個屬性進(jìn)行處理了
- 8.在控制器中直接聲明一個數(shù)組(保存viewModel視圖模型的)锋喜,請求完數(shù)據(jù)后些己,先將字典轉(zhuǎn)換為微博模型,再在創(chuàng)建視圖模型時將微博模型作為參數(shù)傳進(jìn)去嘿般,最后加載cell的數(shù)據(jù)時直接從視圖模型的相關(guān)屬性中取【這是因?yàn)閇視圖模型]中包含[微博模型]段标,[微博模型]中又包含[用戶信息]的模型,所以擁有視圖模型就擁有了另外的模型】
- 9.布局cell:在storyboard添加所有可以顯示的控件博个,并添加約束怀樟,注意:微博正文的寬度約束可以先設(shè)置一個固定的,然后拖線到cell類中通過代碼更改寬度約束為屏幕的寬度減去左右兩邊的間距盆佣,如果在storyboard中直接設(shè)置左右兩邊的間距往堡,在外面計(jì)算正文的高度不準(zhǔn)確
- 10.自定義cell類繼承UITableViewCell來管理storyboard上的cell
- 11.給所有的控件拖線到cell類中械荷,設(shè)置數(shù)據(jù),在cell類中聲明一個viewModel視圖模型屬性虑灰,給這個屬性添加屬性監(jiān)聽器吨瞎,當(dāng)屬性發(fā)送改變時立即給控件設(shè)置值,跟OC中的重寫模型set方法一樣
- 12.布局cell底部工具欄:底部工具欄是是一個UIView穆咐,給UIView設(shè)置個灰色背景颤诀,這個工具欄添加約束,距離Cell底部对湃、左邊崖叫、右邊間距為0,高度為40(根據(jù)需求)拍柒,給工具欄上添加3個UIButton心傀,設(shè)置三個Button距離頂部為1(目的是留出灰色的線), 寬高相同拆讯,且平分工具欄的寬度脂男,注意:設(shè)置按鈕高度約束時需要固定,讓按鈕的底部與cell底部留出20的距離种呐,這樣又留出了分割線效果
- 13.根據(jù)約束自動動態(tài)計(jì)算cell的高度:必須多給微博正文Label添加一個距離底部工具欄頂部的約束為10宰翅,這樣最終會根據(jù)子控件確定父控件的寬度和高度
     注意:(1)要想根據(jù)約束計(jì)算cell的高度,還需要設(shè)置兩個屬性:       tableView.rowHeight = UITableViewAutomaticDimension(自動計(jì)算高度)
    tableView.estimatedRowHeight = 200(估算高度),(2)子控件必須設(shè)置準(zhǔn)確的約束依賴
- 14.獲取配圖數(shù)據(jù)爽室,配圖數(shù)據(jù)是在服務(wù)器返回的status數(shù)組中的pic數(shù)組汁讼,因?yàn)檫@個pic數(shù)組保存又是字典,使用時取值麻煩肮之,所以需要在視圖模型中進(jìn)行處理掉缺,在viewModel中增加一個picURLs卜录,遍歷pic數(shù)組中所有的字典戈擒,取出字典中key對應(yīng)URL,然后將所有的URL添加到picURLs中
- 15.展示配圖:由于配圖使用類似九宮格的布局艰毒,這里可以用CollectionView展示
    -(1).在Home.storyboard中Cell上拖一個collectionView筐高,注意:需要將【微博文本內(nèi)容】控件底部距離【工具條】的約束刪除掉
    -(2).給collectionView添加約束:左側(cè)與頭像對其,與微博文本內(nèi)容控件有10的間距丑瞧,但是寬度和高度的約束不能確定柑土,需要根據(jù)圖片確定,當(dāng)沒有圖片時寬度和高度約束為0绊汹,但是不添加寬度和高度會報(bào)紅色稽屏,可以先隨便設(shè)置個寬度和高度約束,然后根據(jù)圖片動態(tài)的計(jì)算圖片寬度和高度約束
    -(3).對collectionView的寬度和高度約束拖線到HomeViewCell中
    -(4).在cell的viewModel的屬性監(jiān)聽器didSet中計(jì)算西乖,不要在awakeFromNib中計(jì)算狐榔,因?yàn)閍wakeFromNib只會調(diào)用一次坛增,而collectionView的寬度和高約束需要根據(jù)【圖片的個數(shù)】動態(tài)進(jìn)行計(jì)算而會改變的
    -(5).計(jì)算配圖尺寸方式:單獨(dú)抽取一個方法來計(jì)算collectionView的Size:配圖的情況可以分為【沒有配圖】【四張配圖】【其他配圖】
    -(6).這里會報(bào)很多約束相關(guān)的警告:
        -原因:【沒有配圖】的情況collectionView的高度約束設(shè)置為0了,本身我們在給collectionView添加了距離底部工具條頂部的約束為10薄腻,又設(shè)置了微博文本內(nèi)容控件的底部約束距離collectionView頂部為0收捣,當(dāng)collectionView高度約束為0時,這兩個約束就會產(chǎn)生沖突
        -解決方法:改變約束的優(yōu)先級庵楷,可以設(shè)置collectionView距離底部工具條頂部約束的優(yōu)先級小于1000即可罢艾,系統(tǒng)會優(yōu)先使用優(yōu)先級高的約束,把另外一個忽略掉
    -(7).展示collectionView上配圖的數(shù)據(jù)尽纽,正常情況下應(yīng)該設(shè)置collectionView的父控件為數(shù)據(jù)源的咐蚯,但是由于collectionView的父控件TableViewCell類中已經(jīng)做了很多其他邏輯運(yùn)算和代碼,這樣寫在TableViewCell類中會很亂弄贿,所以這里可以自定義PicCollectionView類繼承自UICollectionView來管理這個配圖控件
    -(8).設(shè)置PicCollectionView數(shù)據(jù)源為自己仓蛆,注意:storyboard中無法設(shè)置數(shù)據(jù)源為自己的,因?yàn)樘O果不建議這么做挎春,可以通過代碼來設(shè)置看疙,由于數(shù)據(jù)源只需要設(shè)置一次,可以在awakeFromNib中設(shè)置直奋,并遵守?cái)?shù)據(jù)源方法
    -(9).注冊PicCollectionView的cell:可以通過storyboard中點(diǎn)擊PicCollectionView的cell能庆,給其添加identifier重用標(biāo)識即可,在PicCollectionView的cellForItemAtIndexPath數(shù)據(jù)源方法中通過這個identifier重用標(biāo)識取出對應(yīng)的cell
    -(10).當(dāng)前PicCollectionView的cell大小不正確脚线,需要設(shè)置collectionView的流水布局來設(shè)置itemSzie
     -步驟:(1)先將storyboard中的collectionView拖線到HomeViewCell中搁胆,在awakeFromNib中取出collectionView對應(yīng)的collectionViewLayout,定義用一個常量接收邮绿,(注意:取出的布局是普通布局渠旁,并沒有itemSize屬性),再強(qiáng)制轉(zhuǎn)換為流水布局類型
          (2)直接將之前計(jì)算的每個配圖的寬度和高度其實(shí)就是item的寬度高度船逮,直接拷貝過來就行
    -(11).在PicCollectionView中定義一個picURLs數(shù)組顾腊,然后監(jiān)聽這個數(shù)組didSet發(fā)生改變,只要發(fā)送改變就調(diào)用PicCollectionView的reload()方法刷新數(shù)據(jù)挖胃,然后在PicCollectionView的數(shù)據(jù)源方法中直接通過picURLs數(shù)組獲取數(shù)據(jù)即可
    -(12).在HomeViewCell類中給PicCollectionView中定義的picURLs數(shù)組傳遞數(shù)據(jù)
    -(13).自定義PicCollectionView的cell類杂靶,在這個cell類中添加imageView,讓這個imageView現(xiàn)實(shí)配圖即可酱鸭,由于這個cell比較簡單吗垮,所以不建議單獨(dú)創(chuàng)建一個文件來管理這個類,可以直接在PicCollectionView類中添加這個cell類繼承自UICollectionViewCell凹髓,在storyboard中讓自定義的cell來管理PicCollectionView的cell烁登,就可以在storyboard中給這個cell添加imageView了,最后設(shè)置約束為距離cell上下左右為0即可
    -(14).給cell設(shè)置數(shù)據(jù)蔚舀,將PicCollectionView的cell上的imageView拖線到管理它的這個cell類中饵沧,給這個cell類定義一個模型屬性picURL蚀之,監(jiān)聽picURL屬性didSet發(fā)生改變后就給imageView設(shè)置圖片,注意:需要給picURL傳值捷泞,可以在PicCollectionView類中取出picURLs中每一行對應(yīng)的picURL
緩存配圖
#單張配圖時picCollectionView的尺寸
  -分兩種情況:(1)服務(wù)器返回了圖片的真實(shí)寬高足删,(2)服務(wù)器未提供圖片的真實(shí)寬高
  -第一種情況:服務(wù)器返回了圖片的真實(shí)寬高
    (1)在計(jì)算配圖picCollectionView時:判斷picURLs的數(shù)組元素個數(shù)只要1個的情況,就是單張配圖锁右,然后確定圖片的寬度失受,按比例計(jì)算圖片的高度,然后返回計(jì)算好的圖片寬高即可咏瑟,這種方法非常簡單
    (2)服務(wù)器未提供圖片的真實(shí)寬高時:當(dāng)前項(xiàng)目新浪服務(wù)器就未返回圖片寬度和高度數(shù)據(jù),這種情況做起來非常麻煩拂到,需要先將圖片下載緩存起來,再拿到這個圖片码泞,獲取圖片的寬度和高度兄旬,當(dāng)公司服務(wù)器未返回這些數(shù)據(jù)時,可以直接找服務(wù)器人員溝通加上這些數(shù)據(jù)余寥,以下詳細(xì)步驟
       -(1).在Home控制器中請求數(shù)據(jù)的方法中下載并緩存圖片领铐,注意:一定要下載完圖片在刷新表格
       -(2).下載圖片比較復(fù)雜,單獨(dú)抽取一個方法下載宋舷,給這個方法提供一個【viewModels數(shù)組】參數(shù)绪撵,遍歷viewModels數(shù)組中是所有的viewModel,再遍歷viewModel中picURLs祝蝠,獲取所有picURL(圖片的URL)
       -(3).獲取完圖片的URL后音诈,使用SDWebImageManager.sharedManager對象提供的downloadImageWithURL方法下載圖片
       -(4).所有圖片下載緩存完成后刷新表格:刷新表格必須在圖片下載完成后刷新,這里需要注意的是SDWebImageManager下載圖片是在異步執(zhí)行的绎狭,可以使用GCD的Group隊(duì)列细溅,#1.首先在緩存圖片之前創(chuàng)建一個【組隊(duì)列】dispatch_group_create,#2.在開始下載一張圖片時讓下載操作進(jìn)入組儡嘶,#3.下載完成后離開組喇聊,所以異步操作執(zhí)行完成后,#4.通知【組】并開啟【主隊(duì)列】刷新表格【這樣就實(shí)現(xiàn)所有圖片下載完成后再刷新表格】
       -(5).計(jì)算單張圖片時picCollectionView的寬度和高度
            -1.使用SDWebImageManager通過url字符串從磁盤沙盒中取出圖片(因?yàn)閮?nèi)存中可能會被銷毀)
            -2.直接返回圖片的尺寸社付,注意:SDWebImage內(nèi)部將圖片壓縮的一杯邻耕,所以返回時,返回圖片的width * 2啼辣,height * 2
            -3.此時存在一個問題:當(dāng)單張圖片時,collectionView的流水布局的itemSize會發(fā)生變化御滩,這種情況會報(bào)警告党远,所以流水布局的itemSize也要動態(tài)進(jìn)行設(shè)置富弦,可以在計(jì)算picCollectionView尺寸的方法中設(shè)置沟娱,當(dāng)是單張圖片時腕柜,讓水流布局的itemSize為圖片的width * 2,height * 2砰蠢,另外除單張圖片的情況時台舱,流水布局的itemSize為其他情況計(jì)算好的尺寸
轉(zhuǎn)發(fā)微博
##獲取轉(zhuǎn)發(fā)微博的數(shù)據(jù)
- (1).在微博模型中添加一個轉(zhuǎn)發(fā)微博屬性retweeted_status,對應(yīng)的類型是字典類型
 -(2).由于字典用起來不方便潭流,且轉(zhuǎn)發(fā)的微博retweeted_status本身也是微博灰嫉,所以可以在聲明這個屬性時候熬甫,聲明為XYStatus微博模型類型
 -(3).在自定義構(gòu)造函數(shù)中椿肩,將轉(zhuǎn)發(fā)微博字典轉(zhuǎn)換為微博模型類
##展示轉(zhuǎn)發(fā)微博正文
 -(1).在storyboard中在【微博正文label】下面添加一個【轉(zhuǎn)發(fā)微博正文label】郑象,刪除之前【微博正文label】底部與【配圖collectionView】頂部的約束厂榛,
 -(2).給【轉(zhuǎn)發(fā)微博正文label】添加約束击奶,左側(cè)與iconView左側(cè)對其,頂部與【微博正文label】底部直接約束為15湃望,【轉(zhuǎn)發(fā)微博正文label】需要換行設(shè)置line為0证芭,由于【微博正文label】的寬度已經(jīng)在代碼中計(jì)算好了废士,所以這里可以直接讓【轉(zhuǎn)發(fā)微博正文label】的寬度等于【微博正文label】的寬度約束
 -(3).為了讓子控件決定父控件的高度官硝,選中配圖collectionView設(shè)置它頂部距離【轉(zhuǎn)發(fā)微博正文label】底部的約束為10即可泛源,如果此時約束報(bào)紅色的話达箍,可以修復(fù)下約束
 -(4).將【轉(zhuǎn)發(fā)微博正文label】控件拖線到HomeViewCell中,然后給這個控件設(shè)置數(shù)據(jù)硬纤,需要先判斷【轉(zhuǎn)發(fā)微博模型】的text不為nil的時候才設(shè)置數(shù)據(jù)筝家,當(dāng)然還有判斷為【轉(zhuǎn)發(fā)微博模型】的text為nil的時候就講【轉(zhuǎn)發(fā)微博label】的text設(shè)置為nil溪王,防止循環(huán)利用莹菱,有if就有else
 -(5).獲取轉(zhuǎn)發(fā)微博中screenName道伟,在轉(zhuǎn)發(fā)微博正文前面加上@用戶名
  - 多個條件用where分開蜜徽,多個可選綁定校驗(yàn)用,逗號分隔
##展示轉(zhuǎn)發(fā)微博配圖
 -(1).邏輯分析:一個微博配圖與轉(zhuǎn)發(fā)微博的配圖只會顯示其中一個拘鞋,當(dāng)存放微博配圖的數(shù)組的元素個數(shù)count不為0的時候掐禁,就是有微博配圖傅事,此時顯示微博配圖蹭越,當(dāng)存放微博配圖的數(shù)組的元素個數(shù)count為0的時候响鹃,就沒有微博配圖买置,此時就顯示轉(zhuǎn)發(fā)微博的配圖
 使用三目運(yùn)算符就可以搞定
 -(2).轉(zhuǎn)發(fā)微博的背景
     - 轉(zhuǎn)發(fā)微博的背景可以給其添加一個UIView忿项,讓它成為獨(dú)立的控件轩触,好控制器背景的hidden屬性脱柱,有轉(zhuǎn)發(fā)微博時顯示榨为,沒有轉(zhuǎn)發(fā)微博時隱藏
     - 背景注意是用在轉(zhuǎn)發(fā)微博上面的柠逞,這里把背景放在【轉(zhuǎn)發(fā)微博Label】和【配圖控件】下面即可
     - 給背景添加約束板壮,底部距離工具欄為0绰精,距離控制器view左右都為0笨使,頂部距離微博正文為8(因?yàn)槲⒉┱牡拈g距為15)硫椰,所以我們讓背景的線居中顯示
     - 控制器背景hidden屬性靶草,拖線到HomeViewCell中奕翔,當(dāng)有轉(zhuǎn)發(fā)微博時顯示派继,沒有轉(zhuǎn)發(fā)微博時隱藏
約束細(xì)節(jié)調(diào)整
  建議:細(xì)節(jié)方面的調(diào)整放到最后一起調(diào)整
- 問題1:當(dāng)沒有配圖時驾窟,微博正文與底部工具欄之間的間隙變?yōu)?0绅络,正常應(yīng)該是10的昨稼,這是因?yàn)槲覀冊O(shè)置了微博正文距離配圖的約束10假栓,而配圖又設(shè)置了距離工具欄的約束為10匾荆,雖然設(shè)置了配圖距離工具欄的約束優(yōu)先級較低牙丽,但是當(dāng)沒有配圖的時候距離底部工具欄的約束還是存在的烤芦,所以導(dǎo)致最終兩個約束都存在正好為20
- 解決方法:將配圖距離底部工具欄的約束拖線HomeViewCell中铜涉,當(dāng)沒有配圖時設(shè)置約束為0芙代,當(dāng)有配圖時設(shè)置約束為10
Snip20161001_5.png

- 問題2:與問題1情況相同纹烹,當(dāng)沒有轉(zhuǎn)發(fā)微博時铺呵,配圖和微博正文控件之間的間隙變?yōu)榱?5陪蜻,正常我們希望為10宴卖,這是因?yàn)檗D(zhuǎn)發(fā)微博正文是一個label,他與微博正文之間的間距為15約束肝谭,而轉(zhuǎn)發(fā)微博正文又與配圖有10的約束間距攘烛,那沒轉(zhuǎn)發(fā)微博時坟漱,轉(zhuǎn)發(fā)微博Label之間的這兩個間距約束還是存在的芋齿,所以導(dǎo)致間距為25了
- 解決方法:當(dāng)沒有轉(zhuǎn)發(fā)微博時觅捆,將轉(zhuǎn)發(fā)微博正文距離頂部的約束設(shè)置為0栅炒,有轉(zhuǎn)發(fā)微博的時候再設(shè)置為15


Snip20161001_7.png
計(jì)算cell的高度
##分析:目前cell的高度是根據(jù)約束自動計(jì)算出來的,而且此前設(shè)置約束出現(xiàn)了沖突域携,修改內(nèi)容約束優(yōu)先級為250才解決的秀鞭,內(nèi)容約束默認(rèn)優(yōu)先級為251锋边,我們一般很少使用它豆巨,所以往扔,我們不讓子控件決定父控件的高度
-1.恢復(fù)內(nèi)容約束為251
-2.刪除工具條底部的約束吭服,不讓子控件決定父控件的高度
-3.此時已經(jīng)不能通過子控件的約束來決定父控件的高度了艇棕,就要刪除tableView的自動計(jì)算高度的代碼
##計(jì)算cell的高度
-1.實(shí)現(xiàn)tableView的代理方法heightForRowAtIndexPath
-2.設(shè)置tableView的估算高度:這樣會先調(diào)用cellForRowAtIndexPath再調(diào)用heightForRowAtIndexPath方法
-3.在給cell傳遞視圖模型的時候就要確定cell的高度沼琉,所以計(jì)算cell的高度要在HomeViewCell的視圖模型屬性的監(jiān)聽器中設(shè)置
-4.計(jì)算cell高度的步驟:
    -(1).先調(diào)用layoutIfNeed()方法進(jìn)行強(qiáng)制布局
    -(2).拿到storyboard中工具欄的最大Y值,將工具欄拖線到HomeViewCell中即可拿到瑟慈,因?yàn)楣ぞ邫诘淖畲骙值就是cell的高度
    -(3).在viewModel模型視圖中定義一個cellHeight變量葛碧,將計(jì)算好的cell的高度直接復(fù)制給它保存起來即可
    -(4).由于HomeViewCell的視圖模型屬性添加了屬性監(jiān)聽器进泼,每次有新的cell出現(xiàn)時都會調(diào)用乳绕,也就會重復(fù)計(jì)算cell的高度,這樣不好菠发,所以可以在計(jì)算cell高度時先判斷定義在viewModel中的cellHeight變量是否為0滓鸠,如果為0再進(jìn)行強(qiáng)制布局糜俗,再計(jì)算cell的高度
   -(5)在tableView的代理方法heightForRowAtIndexPath中悠抹,先通過viewModels數(shù)組獲取viewModel模型桥温,再返回viewModel中的cellHeight即可
下拉刷新
- 蘋果提供了UIRefreshController刷新控件,其繼承自UITableViewController
-  蘋果的Xcode在編譯時會自動把OC代碼轉(zhuǎn)換為Swift代碼
##當(dāng)前項(xiàng)目為了方便使用MJRefresh即可解決
-1.給HomeViewController添加下拉刷新控件氛谜,使用MJRefreshNormalHeader創(chuàng)建Header
-2.設(shè)置header各種狀態(tài)下的文字
-3.讓Header加載最新的數(shù)據(jù),在當(dāng)前類中定義一個加載最新數(shù)據(jù)的方法
-4.設(shè)置tableView的mj_header為創(chuàng)建的header
-5.開始刷新杨何,有下拉刷新以后就沒必要主動調(diào)用加載新數(shù)據(jù)的方法了
-6.讓header直接調(diào)用HomeViewController中加載數(shù)據(jù)的方法
-7.請求完成數(shù)據(jù)后結(jié)束刷新
-當(dāng)前存在的問題:每次下拉刷新時并沒有請求到最新的數(shù)據(jù)危虱,這是因?yàn)槲覀冎罢埱髷?shù)據(jù)傳遞的參數(shù)不夠埃跷,我們只傳了access_token,只會請求最新的20條微博剪勿,但是我們并不想要最新的微博厕吉,而是要比當(dāng)前界面上第一條微博新的微博
- 分析:每天微博都有一個ID赴涵,比較新的微博ID肯定比現(xiàn)在的微博要大
-解決方法:需要再傳遞一個參數(shù)since_id扇苞,這個參數(shù)會返回比當(dāng)前時間更新鳖敷,微博id更大的微博定踱,比如我們傳了一個since_id為2000001崖媚,那么服務(wù)器返回的微博的ID肯定要比這個ID要大的
  -(1)請求數(shù)據(jù)前要獲取since_id,讓其默認(rèn)為0荠呐,如果加載新數(shù)據(jù)就是下拉刷新時泥张,since_id等于viewModels數(shù)組中第一個viewModel的微博模型的mid屬性媚创,如果第一個viewModel的微博模型的mid屬性取不到就讓since_id為0
  -(2)在網(wǎng)絡(luò)工具類封裝的請求數(shù)據(jù)方法上增加一個Int類型since_id參數(shù)齿诉,然后在拼接參數(shù)時將其拼接進(jìn)去筝野,并在拼接參數(shù)時將since_id包裝為字符串類型
  -(3)在HomeViewController中請求網(wǎng)絡(luò)就使用這個新的方法請求
  -(4)當(dāng)下拉刷新數(shù)據(jù)時,將新的數(shù)據(jù)應(yīng)該放在viewModels數(shù)組的最前面粤剧,而不是直接添加到后面歇竟,所以不能使用append方法,這樣會導(dǎo)致數(shù)據(jù)有誤抵恋,但是如果使用inset方法將新數(shù)據(jù)插入到模型數(shù)組的前面也存在問題:比如當(dāng)我們一次請求2條數(shù)據(jù)回來時焕议,會取出最新的一條先inset插入到模型數(shù)組的前面弧关,到第二條數(shù)據(jù)在插入時盅安,就會插入到最新的那條數(shù)據(jù)的前面了唤锉,這樣就導(dǎo)致數(shù)據(jù)順序錯誤,因?yàn)檫@2條數(shù)據(jù)第1條先插入的最新别瞭,但是第2條數(shù)據(jù)卻插入在最上面了
  -(5)插入數(shù)據(jù)最好的解決方法:(將要插入的數(shù)據(jù)放在數(shù)組中窿祥,將這個數(shù)組直接拼接在原來的數(shù)組的前面)1.在遍歷服務(wù)器返回的數(shù)據(jù)之前,先定義一個臨時數(shù)組變量蝙寨,2.每次遍歷服務(wù)器返回的新數(shù)據(jù)時晒衩,轉(zhuǎn)換為模型后,將模型先存放臨時數(shù)組tempViewModels中墙歪,3.將臨時數(shù)組tempViewModels直接拼接在大數(shù)組viewModels的前面听系,swift中可以這樣self. viewModels = tempViewModels + viewModels
  -(6)注意:在緩存圖片時只緩存最新的圖片即可,不用緩存大數(shù)組中最新的數(shù)據(jù)
上拉加載更多
-1.給tableView添加一個mj_footer虹菲,使用MJRefreshAutoFooter 創(chuàng)建一個下拉刷新控件靠胜,MJRefreshAutoFooter創(chuàng)建的footer沒有上拉加載更多的文字
-2.添加一個方法loadMoreStatus,這個方法調(diào)用請求數(shù)據(jù)的方法即可毕源,給這個方法傳false浪漠,isNewData屬性就會為false,就不會加載最新的數(shù)據(jù)脑豹,就會去加載更多
-3.請求更多數(shù)據(jù)還需要傳max_id參數(shù)郑藏,若傳此參數(shù)服務(wù)器返回的的微博ID會小于當(dāng)前顯示的最后一條微博ID,根據(jù)是否是最新數(shù)據(jù)來判斷
-4.在網(wǎng)絡(luò)工具類中在請求數(shù)據(jù)方法中瘩欺,再添加一個參數(shù)max_id,然后把這個參數(shù)拼接到請求參數(shù)中
-5.此時要對轉(zhuǎn)換完成的模型添加數(shù)組進(jìn)行處理,根據(jù)isNewData來判斷拌牲,如果是新數(shù)據(jù)就添加到大數(shù)組的前面俱饿,舊數(shù)據(jù)就添加到后面
添加下拉刷新時提示更新微博數(shù)據(jù)提示的Label
-1.在HomeViewController中定義一個懶加載的提示UILabel變量
-2.在控制器viewDidLoad方法中將這個Label添加到導(dǎo)航條navigationBar上,并設(shè)置frame塌忽,最好不要添加到tableView上拍埠,因?yàn)橥蟿觮ableView時,這個Lable也會跟著tableView一起滾動土居,當(dāng)前需求不需要Label跟著tableView一起滾動
 注意:再添加提示Label到導(dǎo)航條上時枣购,不要使用addSubviews方法,使用insertSubviews方法傳入到導(dǎo)航欄的里面就是0擦耀,此時如果看到看到導(dǎo)航欄的顏色和狀態(tài)欄的顏色都有提示Lable顏色模糊的效果時棉圈,這是因?yàn)槟J(rèn)情況下導(dǎo)航欄有毛玻璃效果(高斯模糊),他會將后面的模糊化眷蜓,那么后面的顏色就會擴(kuò)散開
-3.設(shè)置提示Lable的frame分瘾,并設(shè)置默認(rèn)情況下就隱藏,在刷新表格后就顯示提示Lable吁系,并設(shè)置動畫德召,完成動畫后隱藏
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末白魂,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子上岗,更是在濱河造成了極大的恐慌福荸,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肴掷,死亡現(xiàn)場離奇詭異逞姿,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)捆等,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進(jìn)店門滞造,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人栋烤,你說我怎么就攤上這事谒养。” “怎么了明郭?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵买窟,是天一觀的道長。 經(jīng)常有香客問我薯定,道長始绍,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任话侄,我火速辦了婚禮亏推,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘年堆。我一直安慰自己吞杭,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布变丧。 她就那樣靜靜地躺著芽狗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪痒蓬。 梳的紋絲不亂的頭發(fā)上童擎,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天,我揣著相機(jī)與錄音攻晒,去河邊找鬼顾复。 笑死,一個胖子當(dāng)著我的面吹牛炎辨,可吹牛的內(nèi)容都是我干的捕透。 我是一名探鬼主播,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼乙嘀!你這毒婦竟也來了末购?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤虎谢,失蹤者是張志新(化名)和其女友劉穎盟榴,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體婴噩,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡擎场,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了几莽。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片迅办。...
    茶點(diǎn)故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖章蚣,靈堂內(nèi)的尸體忽然破棺而出站欺,到底是詐尸還是另有隱情,我是刑警寧澤纤垂,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布矾策,位于F島的核電站,受9級特大地震影響峭沦,放射性物質(zhì)發(fā)生泄漏贾虽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一吼鱼、第九天 我趴在偏房一處隱蔽的房頂上張望蓬豁。 院中可真熱鬧,春花似錦蛉抓、人聲如沸庆尘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至矛辕,卻和暖如春笑跛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背聊品。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工飞蹂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人翻屈。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓陈哑,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子惊窖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 在簡書我寫了快四萬字了刽宪,我發(fā)現(xiàn)至今我還沒有寫過愛情或描述過愛情。 當(dāng)然界酒,這也沒什麼奇怪圣拄。許多人認(rèn)為,女人的愛情也會...
    瑪格麗特姑姑閱讀 1,604評論 11 41
  • 這兩天跟著伊伊小盆友游學(xué)山西毁欣,每走到一處都要寫生庇谆,回到酒店還有晚課,一天高強(qiáng)度的學(xué)習(xí)和訓(xùn)練凭疮,孩子們開心地畫...
    伊姐姐姐閱讀 393評論 1 3
  • 在這個美食掃地的中國逝淹,越來越多的年輕人肚子越來越大,太多的美食誘惑桶唐,我們這個吃貨怎么能忍得住栅葡,為了拉動經(jīng)濟(jì)...
    瘦小花閱讀 320評論 0 1
  • 今天外面在呼呼的刮雪風(fēng),也停電了尤泽,自從回了新疆欣簇,幾乎沒有享受過4g,這會兒也快天黑了(說完這句話突然感覺一下子暗了...
    竹一姑娘閱讀 373評論 0 6