swift筆記(三)

1.獲取未授權(quán)Request

// 1.定義字符串保存登錄界面URL
        let urlStr = "https://api.weibo.com/oauth2/authorize?client_id=4129759360&redirect_uri=http://www.520it.com"
        // 2.創(chuàng)建URL
        guard let url = URL(string: urlStr) else
        {
            return
        }
        // 3.創(chuàng)建Request
        let request = URLRequest(url: url)
        
        // 4.加載登錄界面
        customWebView.loadRequest(request)

2.獲取已經(jīng)授權(quán)Request

extension OAuthViewController: UIWebViewDelegate
{
    // 該方法每次請求都會調(diào)用
    // 如果返回false代表不允許請求, 如果返回true代表允許請求
    func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
        /*
        登錄界面: https://api.weibo.com/oauth2/authorize?client_id=4129759360&redirect_uri=http://www.520it.com 
        輸入賬號密碼之后: https://api.weibo.com/oauth2/authorize
        取消授權(quán): http://www.520it.com/?error_uri=%2Foauth2%2Fauthorize&error=access_denied&error_description=user%20denied%20your%20request.&error_code=21330
        授權(quán):http://www.520it.com/?code=c2796542e264da89367f993131e6c904
        通過觀察
        1.如果是授權(quán)成功獲取失敗都會跳轉(zhuǎn)到授權(quán)回調(diào)頁面
        2.如果授權(quán)回調(diào)頁面包含code=就代表授權(quán)成功, 需要截取code=后面字符串
        3.而且如果是授權(quán)回調(diào)頁面不需要顯示給用戶看, 返回false
        */
        // 1.判斷當前是否是授權(quán)回調(diào)頁面
        guard let urlStr = request.url?.absoluteString else
        {
            return false
        }
        if !urlStr.hasPrefix("http://www.520it.com/")
        {
            NJLog("不是授權(quán)回調(diào)頁面")
            return true
        }
        
        NJLog("是授權(quán)回調(diào)頁面")
        // 2.判斷授權(quán)回調(diào)地址中是否包含code=
        // URL的query屬性是專門用于獲取URL中的參數(shù)的, 可以獲取URL中?后面的所有內(nèi)容
        let key = "code="
        if urlStr.contains(key)
        {
            let code = request.url!.query?.substring(from: key.endIndex)
            NJLog(code)
            return false
        }
        NJLog("授權(quán)失敗")
        return false
    }
}

3.換取AccessToken

  /// 利用RequestToken換取AccessToken
    private func loadAccessToken(codeStr: String?)
    {
        guard let code = codeStr else
        {
            return
        }
        // 注意:redirect_uri必須和開發(fā)中平臺中填寫的一模一樣
        // 1.準備請求路徑
        let path = "oauth2/access_token"
        // 2.準備請求參數(shù)
        let parameters = ["client_id": "4129759360", "client_secret": "98392a5714c6194f5aee796d971fe0ef", "grant_type": "authorization_code", "code": code, "redirect_uri": "http://www.520it.com"]
        // 3.發(fā)送POST請求
        NetworkTools.shareInstance.POST(path, parameters: parameters, success: { (task: NSURLSessionDataTask, dict: AnyObject) -> Void in
            NJLog(dict)
            }) { (task: NSURLSessionDataTask?, error: NSError) -> Void in
                NJLog(error)
        }
    }

4.保存

let account = UserAccount(dict: objc as! [String : AnyObject])
account.saveAccount()


UserAccount.swift
import UIKit

class UserAccount: NSObject, NSCoding {
    
    var access_token: String?
    var expires_in: Int = 0
    var uid: String?
    
    // MARK: - 生命周期方法
    init(dict: [String: AnyObject])
    {
        super.init()
        // 如果要想初始化方法中使用KVC必須先調(diào)用super.init初始化對象
        // 如果屬性是基本數(shù)據(jù)類型, 那么建議不要使用可選類型, 因為基本數(shù)據(jù)類型的可選類型在super.init()方法中不會分配存儲空間
        self.setValuesForKeysWithDictionary(dict)
    }
    
    // 當KVC發(fā)現(xiàn)沒有對應的key時就會調(diào)用
    override func setValue(value: AnyObject?, forUndefinedKey key: String) {
        
    }
    override var description: String {
        return "abc"
    }
    
    // MARK: - 外部控制方法
    // 歸檔模型
    func saveAccount() -> Bool
    {
        // 1.獲取緩存目錄的路徑
        let path = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.CachesDirectory, NSSearchPathDomainMask.UserDomainMask, true).last!
        // 2.生成緩存路徑
        let filePath = (path as NSString).stringByAppendingPathComponent("useraccount.plist")
        NJLog(filePath)
        // 3.歸檔對象
        return NSKeyedArchiver.archiveRootObject(self, toFile: filePath)
    }
    
    /// 定義屬性保存授權(quán)模型
    static var account: UserAccount?
    // 解歸檔模型
    class func loadUserAccount() -> UserAccount?
    {
        // 1.判斷是否已經(jīng)加載過了
        if UserAccount.account != nil{
            NJLog("已經(jīng)有加載過")
            // 直接返回
            return UserAccount.account
        }
        
        // 2.嘗試從文件中加載
        NJLog("還沒有加載過")
        // 1.獲取緩存目錄的路徑
        let path = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.CachesDirectory, NSSearchPathDomainMask.UserDomainMask, true).last!
        // 2.生成緩存路徑
        let filePath = (path as NSString).stringByAppendingPathComponent("useraccount.plist")
        // 3.解歸檔對象
        guard let account = NSKeyedUnarchiver.unarchiveObjectWithFile(filePath) as? UserAccount else
        {
            return UserAccount.account
        }
        UserAccount.account = account
        
        return UserAccount.account
    }
    
    /// 判斷用戶是否登錄
    class func isLogin() -> Bool {
        return UserAccount.loadUserAccount() != nil
    }
    
    // MARK: - NSCoding
    func encodeWithCoder(aCoder: NSCoder)
    {
        aCoder.encodeObject(access_token, forKey: "access_token")
        aCoder.encodeInteger(expires_in, forKey: "expires_in")
        aCoder.encodeObject(uid, forKey: "uid")
    }
    
    required init?(coder aDecoder: NSCoder)
    {
        self.access_token = aDecoder.decodeObjectForKey("access_token") as? String
        self.expires_in = aDecoder.decodeIntegerForKey("expires_in") as Int
        self.uid = aDecoder.decodeObjectForKey("uid") as? String
    }
}

5.保存優(yōu)化

import UIKit

class UserAccount: NSObject, NSCoding {
    
    var access_token: String?
    var expires_in: Int = 0
    var uid: String?
    
    // MARK: - 生命周期方法
    init(dict: [String: AnyObject])
    {
        super.init()
        // 如果要想初始化方法中使用KVC必須先調(diào)用super.init初始化對象
        // 如果屬性是基本數(shù)據(jù)類型, 那么建議不要使用可選類型, 因為基本數(shù)據(jù)類型的可選類型在super.init()方法中不會分配存儲空間
        self.setValuesForKeysWithDictionary(dict)
    }
    
    // 當KVC發(fā)現(xiàn)沒有對應的key時就會調(diào)用
    override func setValue(value: AnyObject?, forUndefinedKey key: String) {
        
    }
    override var description: String {
        // 將模型轉(zhuǎn)換為字典
        let property = ["access_token", "expires_in", "uid"]
        let dict = dictionaryWithValuesForKeys(property)
        // 將字典轉(zhuǎn)換為字符串
        return "\(dict)"
    }
    
    // MARK: - 外部控制方法
    // 歸檔模型
    func saveAccount() -> Bool
    {
        /*
        // 1.獲取緩存目錄的路徑
        let path = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.CachesDirectory, NSSearchPathDomainMask.UserDomainMask, true).last!
        // 2.生成緩存路徑
        let filePath = (path as NSString).stringByAppendingPathComponent("useraccount.plist")
        NJLog(filePath)
        */
        // 3.歸檔對象
        return NSKeyedArchiver.archiveRootObject(self, toFile: UserAccount.filePath)
    }
    
    /// 定義屬性保存授權(quán)模型
    static var account: UserAccount?
//    static let filePath: String = (NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.CachesDirectory, NSSearchPathDomainMask.UserDomainMask, true).last! as NSString).stringByAppendingPathComponent("useraccount.plist")
    static let filePath: String = "useraccount.plist".cachesDir()
    
    // 解歸檔模型
    class func loadUserAccount() -> UserAccount?
    {
        // 1.判斷是否已經(jīng)加載過了
        if UserAccount.account != nil{
            NJLog("已經(jīng)有加載過")
            // 直接返回
            return UserAccount.account
        }
        
        // 2.嘗試從文件中加載
        NJLog("還沒有加載過")
        /*
        // 1.獲取緩存目錄的路徑
        let path = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.CachesDirectory, NSSearchPathDomainMask.UserDomainMask, true).last!
        // 2.生成緩存路徑
        let filePath = (path as NSString).stringByAppendingPathComponent("useraccount.plist")
        */
        
        // 3.解歸檔對象
        guard let account = NSKeyedUnarchiver.unarchiveObjectWithFile(UserAccount.filePath) as? UserAccount else
        {
            return UserAccount.account
        }
        UserAccount.account = account
        
        return UserAccount.account
    }
    
    /// 判斷用戶是否登錄
    class func isLogin() -> Bool {
        return UserAccount.loadUserAccount() != nil
    }
    
    // MARK: - NSCoding
    func encodeWithCoder(aCoder: NSCoder)
    {
        aCoder.encodeObject(access_token, forKey: "access_token")
        aCoder.encodeInteger(expires_in, forKey: "expires_in")
        aCoder.encodeObject(uid, forKey: "uid")
    }
    
    required init?(coder aDecoder: NSCoder)
    {
        self.access_token = aDecoder.decodeObjectForKey("access_token") as? String
        self.expires_in = aDecoder.decodeIntegerForKey("expires_in") as Int
        self.uid = aDecoder.decodeObjectForKey("uid") as? String
    }
}


6.時間處理

 /// 從授權(quán)那一刻開始, 多少秒之后過期時間
    var expires_in: Int = 0
        {
        didSet{
            // 生成正在過期時間
            expires_Date = NSDate(timeIntervalSinceNow: NSTimeInterval(expires_in))
        }
    }
    /// 真正過期時間
    var expires_Date: NSDate?




guard let date = account.expires_Date where date.compare(NSDate()) != NSComparisonResult.OrderedAscending  else
        {
            NJLog("過期了")
            return nil
        }

7.獲取用戶數(shù)據(jù)

/// 獲取用戶信息
    func loadUserInfo(finished: (account: UserAccount?, error: NSError?)->())
    {
        // 斷言
        // 斷定access_token一定是不等于nil的, 如果運行的時access_token等于nil, 那么程序就會崩潰, 并且報錯
        assert(access_token != nil, "使用該方法必須先授權(quán)")
        
        // 1.準備請求路徑
        let path = "2/users/show.json"
        // 2.準備請求參數(shù)
        let parameters = ["access_token": access_token!, "uid": uid!]
        // 3.發(fā)送GET請求
        NetworkTools.shareInstance.GET(path, parameters: parameters, success: { (task, objc) -> Void in
            
            let dict = objc as! [String: AnyObject]
            
            // 1.取出用戶信息
            self.avatar_large = dict["avatar_large"] as? String
            self.screen_name = dict["screen_name"] as? String
            
            // 2.保存授權(quán)信息
//            self.saveAccount()
            finished(account: self, error: nil)
            
            }) { (task, error) -> Void in

                finished(account: nil, error: error)
        }
    }

8.新版本特性

import UIKit
import SnapKit

class NewfeatureViewController: UIViewController {
    /// 新特性界面的個數(shù)
    private var maxCount = 4
    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }
}

extension NewfeatureViewController: UICollectionViewDataSource
{
    
    // 1.告訴系統(tǒng)有多少組
    func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
        return 1
    }
    // 2.告訴系統(tǒng)每組多少行
    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return maxCount
    }
    // 3.告訴系統(tǒng)每行顯示什么內(nèi)容
    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        // 1.獲取cell
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("newfeatureCell", forIndexPath: indexPath) as! XMGNewfeatureCell
        cell.backgroundColor = (indexPath.item % 2 == 0) ? UIColor.redColor() : UIColor.purpleColor()
        // 2.設置數(shù)據(jù)
        cell.index = indexPath.item
        
        // 3.返回cell
        return cell
    }
}

extension NewfeatureViewController: UICollectionViewDelegate
{
    func collectionView(collectionView: UICollectionView, didEndDisplayingCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) {
        // 注意: 傳入的cell和indexPath都是上一頁的, 而不是當前頁
//        NJLog(indexPath.item)

        // 1.手動獲取當前顯示的cell對應的indexPath
        let index = collectionView.indexPathsForVisibleItems().last!
        NJLog(index.item)
        // 2.根據(jù)指定的indexPath獲取當前顯示的cell
        let currentCell = collectionView.cellForItemAtIndexPath(index) as! XMGNewfeatureCell
        // 3.判斷當前是否是最后一頁
        if index.item == (maxCount - 1)
        {
            // 做動畫
            currentCell.startAniamtion()
        }
    }
}

// MARK: - 自定義Cell
class XMGNewfeatureCell: UICollectionViewCell
{
    var index: Int = 0
        {
        didSet{

            // 1.生成圖片名稱
            let name = "new_feature_\(index + 1)"
            // 2.設置圖片
            iconView.image = UIImage(named: name)
            startButton.hidden = true
        }
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        
        // 初始化UI
        setupUI()
    }
    
    // MARK: - 外部控制方法
    func startAniamtion()
    {
        startButton.hidden = false
        // 執(zhí)行放大動畫
        /*
        第一個參數(shù): 動畫時間
        第二個參數(shù): 延遲時間
        第三個參數(shù): 震幅 0.0~1.0, 值越小震動越列害
        第四個參數(shù): 加速度, 值越大震動越列害
        第五個參數(shù): 動畫附加屬性
        第六個參數(shù): 執(zhí)行動畫的block
        第七個參數(shù): 執(zhí)行完畢后回調(diào)的block
        */
        startButton.transform = CGAffineTransformMakeScale(0.0, 0.0)
        startButton.userInteractionEnabled = false
        UIView.animateWithDuration(2.0, delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 10, options: UIViewAnimationOptions(rawValue: 0), animations: { () -> Void in
            self.startButton.transform = CGAffineTransformIdentity
            
            }, completion: { (_) -> Void in
                self.startButton.userInteractionEnabled = true
        })
    }
    
    // MARK: - 內(nèi)部控制方法
    private func setupUI()
    {
        // 1.添加子控件
       contentView.addSubview(iconView)
       contentView.addSubview(startButton)
        
        // 2.布局子控件
        /*
        iconView.translatesAutoresizingMaskIntoConstraints = false
        var cons = NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[iconView]-0-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["iconView": iconView])
        cons += NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[iconView]-0-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["iconView": iconView])
        contentView.addConstraints(cons)
        */
        iconView.snp_makeConstraints { (make) -> Void in
//            make.left.equalTo(0)
//            make.right.equalTo(0)
//            make.top.equalTo(0)
//            make.bottom.equalTo(0)
            make.edges.equalTo(0)
        }
        
        startButton.snp_makeConstraints { (make) -> Void in
            make.centerX.equalTo(contentView)
            make.bottom.equalTo(contentView).offset(-160)
        }
    }
    
    @objc private func startBtnClick()
    {
        NJLog("")
    }

    
    // MARK: - 懶加載
    /// 圖片容器
    private lazy var iconView = UIImageView()
    
    /// 開始按鈕
    private lazy var startButton: UIButton = {
       let btn = UIButton(imageName: nil, backgroundImageName: "new_feature_button")
        btn.addTarget(self, action: Selector("startBtnClick"), forControlEvents: UIControlEvents.TouchUpInside)
        return btn
    }()
}

// MARK: - 自定義布局
class XMGNewfeatureLayout: UICollectionViewFlowLayout
{
    // 準備布局
    override func prepareLayout() {
        // 1.設置每個cell的尺寸
        itemSize = UIScreen.mainScreen().bounds.size
        // 2.設置cell之間的間隙
        minimumInteritemSpacing = 0
        minimumLineSpacing = 0
        // 3.設置滾動方向
        scrollDirection = UICollectionViewScrollDirection.Horizontal
        
        // 4.設置分頁
        collectionView?.pagingEnabled = true
        // 5.禁用回彈
        collectionView?.bounces = false
        // 6.取出滾動條
        collectionView?.showsHorizontalScrollIndicator = false
        collectionView?.showsVerticalScrollIndicator = false
    }
}

9.檢查新版本

/// 判斷是否有新版本
    private func isNewVersion() -> Bool
    {
        // 1.加載info.plist
        // 2.獲取當前軟件的版本號
        let currentVersion = NSBundle.mainBundle().infoDictionary!["CFBundleShortVersionString"] as! String
        // 3.獲取以前的軟件版本號?
        let defaults = NSUserDefaults.standardUserDefaults()
        let sanboxVersion = (defaults.objectForKey("xxoo") as? String) ?? "0.0"
        // 4.用當前的版本號和以前的版本號進行比較
        // 1.0  0.0
        if currentVersion.compare(sanboxVersion) == NSComparisonResult.OrderedDescending
        {
            // 如果當前的大于以前的, 有新版本
            NJLog("有新版本")
            // 如果有新版本, 就利用新版本的版本號更新本地的版本號
            
            defaults.setObject(currentVersion, forKey: "xxoo")
            defaults.synchronize() // iOS7以前需要寫, iOS7以后不用寫
            return true
        }
        NJLog("沒有新版本")
        return false
    }

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末桐玻,一起剝皮案震驚了整個濱河市嬉挡,隨后出現(xiàn)的幾起案子菜循,更是在濱河造成了極大的恐慌惠窄,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件挠进,死亡現(xiàn)場離奇詭異匪蟀,居然都是意外死亡提岔,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進店門主巍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來冠息,“玉大人,你說我怎么就攤上這事孕索」浼瑁” “怎么了?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵搞旭,是天一觀的道長散怖。 經(jīng)常有香客問我,道長肄渗,這世上最難降的妖魔是什么镇眷? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮翎嫡,結(jié)果婚禮上欠动,老公的妹妹穿的比我還像新娘。我一直安慰自己惑申,他們只是感情好具伍,可當我...
    茶點故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著圈驼,像睡著了一般人芽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上碗脊,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天啼肩,我揣著相機與錄音橄妆,去河邊找鬼。 笑死祈坠,一個胖子當著我的面吹牛害碾,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播赦拘,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼慌随,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了躺同?” 一聲冷哼從身側(cè)響起阁猜,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蹋艺,沒想到半個月后剃袍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡捎谨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年民效,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片涛救。...
    茶點故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡畏邢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出检吆,到底是詐尸還是另有隱情舒萎,我是刑警寧澤,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布蹭沛,位于F島的核電站臂寝,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏摊灭。R本人自食惡果不足惜交煞,卻給世界環(huán)境...
    茶點故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望斟或。 院中可真熱鬧素征,春花似錦、人聲如沸萝挤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春渤早,著一層夾襖步出監(jiān)牢的瞬間富腊,已是汗流浹背豫尽。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工犹芹, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留恢口,地道東北人唧喉。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓呆躲,卻偏偏與公主長得像异逐,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子插掂,可洞房花燭夜當晚...
    茶點故事閱讀 44,960評論 2 355

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