以后备用技术

Swift项目新浪微博

2018-03-18  本文已影响0人  恒筠

第一节

《The Swift Programming Language》

http://numbbbbb.gitbooks.io/-the-swift-programming-language-/参考资料

if分支语句

guard的使用

* guard 条件表达式 else {
*     // 条换语句
*     break
* }
* 语句组

注意:guard必须用在函数中

switch分支

while和do while循环

在swift3.0中取消了传统的for循坏

for循环

在swift3.0中取消了传统的for循坏
那么我们如果要在swift中范旭遍历

for i in (0..<10).reverse(){
         print(i)
}

字符串

let min = 3
let second = 4

let time = String(format: "%02d:%02d", arguments: [min, second])

数组

// 设置遍历的区间
for item in array[0..<2] {
    print(item)
}
var array = ["why", "lmj","lnj"]
var array1 = ["yz", "wsz"]
var array2 = array + array1;

字典

字典跟数组一样也是一个泛型集合
字典的遍历

// 遍历字典中所有的值
for value in dict.values {
    print(value)
}
// 遍历字典中所有的键
for key in dict.keys {
    print(key)
}

// 遍历所有的键值对
for (key, value) in dict {
    print(key)
    print(value)
}

元组

元组的简单使用

let error = (404, "Not Found")
print(error.0)
print(error.1)

// 写法二:
let error = (errorCode : 404, errorInfo : "Not Found")
print(error.errorCode)
print(error.errorInfo)

// 写法三:
let (errorCode, errorIno) = (404, "Not Found")
print(errorCode)
print(errorIno)

可选类型

let name : Optional<String> = nil

// 写法二:定义可选类型,语法糖(常用)
let name : String? = nil

可选绑定

//原理:首先判断等号左边的值是否为空,如果为空就不执行大括号内的代码,如果不为空那么会把值赋值给等号后边,然后执行大括号内的代码
if let str = string {
    print(str)
}
//可选类型+可选绑定让我们的swift代码更加严谨

函数的使用注意

func makecoffee(type :String = "卡布奇诺") -> String {
    return "制作一杯\(type)咖啡。"
}

let coffee1 = makecoffee("拿铁")
let coffee2 = makecoffee()
func sum(numbers:Double...) -> Double {
    var total: Double = 0
    for number in numbers {
        total += number
    }
    return total
}
//其实可变参数,相当于数组

sum(100.0, 20, 30)
sum(30, 80)
指针的传递
func swap1(inout a : Int, inout b : Int) {
    let temp = a
    a = b
    b = temp

    print("a:\(a), b:\(b)")
}

swap1(&a, b: &b)
print("a:\(a), b:\(b)")

Swift中类的使用

监听属性的变化

类的构造函数

class Person: NSObject {
    // 结构体或者类的类型,必须是可选类型.因为不能保证一定会赋值
    var name : String?

    // 基本数据类型不能是可选类型,否则KVC无法转化
    var age : Int = 0

    // 自定义构造函数,会覆盖init()函数
    init(dict : [String : NSObject]) {
        // 必须先初始化对象
        super.init()

        // 调用对象的KVC方法字典转模型
        setValuesForKeysWithDictionary(dict)
    }
}

// 创建一个Person对象
let dict = ["name" : "why", "age" : 18]
let p = Person(dict: dict)

OC中Block的复习

block的写法:
    类型:
    返回值(^block的名称)(block的参数)

    值:
    ^(参数列表) {
        // 执行的代码
    };

闭包

闭包的写法:
    类型:(形参列表)->(返回值)
    技巧:初学者定义闭包类型,直接写()->().再填充参数和返回值

    值:
    {
        (形参) -> 返回值类型 in
        // 执行代码
    }
    // 开发中建议该写法
    httpTool.loadRequest {
        print("回到主线程", NSThread.currentThread());
    }

闭包的循坏引用

    httpTool.loadData {[weak self] () -> () in
        print("加载数据完成,更新界面:", NSThread.currentThread())
        self!.view.backgroundColor = UIColor.redColor()
    }
httpTool.loadData {[unowned self] () -> () in
        print("加载数据完成,更新界面:", NSThread.currentThread())
        self.view.backgroundColor = UIColor.redColor()
    }

懒加载

    // 懒加载的本质是,在第一次使用的时候执行闭包,将闭包的返回值赋值给属性
    // lazy的作用是只会赋值一次
    lazy var array : [String] = {
        () -> [String] in
        return ["why", "lmj", "lnj"]
    }()

第二节

通过json动态创建控制器

override func viewDidLoad() {
        super.viewDidLoad()

        // 1.加载json中的数据
        // 1.1.获取路径
        let path = NSBundle.mainBundle().pathForResource("MainVCSettings.json", ofType: nil)
        // 1.2.加载数据
        guard let data = NSData(contentsOfFile: path!) else {
            XMGLog("没有获取到json数据")
            addChildViewController()
            return
        }

        // 1.3.通过序列化获取内容
        guard let childVcArray = try? NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as! [[String : AnyObject]] else {
            print("没有获取到值")
            addChildViewController()
            return
        }

        // 1.4.遍历数组,并且创建控制器
        for dict in childVcArray {
            // 1.取出类名称
            let vcName = dict["vcName"] as! String

            // 2.取出标题
            let title = dict["title"] as! String

            // 3.取出图标名称
            let imageName = dict["imageName"] as! String

            // 4.创建控制器
            addChildViewController(vcName, imageName: imageName, title: title)
        }
    }

    private func addChildViewController() {
        self.addChildViewController("HomeViewController", imageName: "tabbar_home", title: "主页")
        self.addChildViewController("MessageViewController", imageName: "tabbar_message_center", title: "消息")
        self.addChildViewController("DiscoverViewController", imageName: "tabbar_discover", title: "广场")
        self.addChildViewController("ProfileViewController", imageName: "tabbar_profile", title: "我")
    }

    private func addChildViewController(childCVcName: String, imageName : String, title : String) {

        // 0.获取命名空间
        guard let executable = NSBundle.mainBundle().infoDictionary!["CFBundleExecutable"] as? String else {
            XMGLog("没有命名空间")
            return
        }

        // 1.获取对应的类
        guard let childVcClass : AnyClass = NSClassFromString(executable + "." + childCVcName) else {
            XMGLog("转成对应的类失败")
            return
        }

        // 2.拿到对应的类
        let childClass = childVcClass as! UITableViewController.Type
        let childVc = childClass.init()

        // 3.创建自控制器
        let homeNav = UINavigationController(rootViewController: childVc)

        // 4.设置标题
        childVc.title = title
        childVc.tabBarItem.selectedImage = UIImage(named: imageName + "_highlighted")
        childVc.tabBarItem.image = UIImage(named: imageName)

        // 5.添加到UITabbarController
        self.addChildViewController(homeNav)
    }

Swift的异常处理

方式一:try方式 程序员手动捕捉异常
                do {
                    try NSJSONSerialization.JSONObjectWithData(jsonData, options: .MutableContainers)
                } catch {
                    // error异常的对象
                    print(error)
                }
        
            方式二:try?方式(常用方式) 系统帮助我们处理异常,如果该方法出现了异常,则该方法返回nil.如果没有异常,则返回对应的对象
                guard let anyObject = try? NSJSONSerialization.JSONObjectWithData(jsonData, options: .MutableContainers) else {
                    return
                }
            
            方式三:try!方法(不建议,非常危险) 直接告诉系统,该方法没有异常.注意:如果该方法出现了异常,那么程序会报错(崩溃)
                let anyObject = try! NSJSONSerialization.JSONObjectWithData(jsonData, options: .MutableContainers)

遍历构造函数

   convenience : 便利,使用convenience修饰的构造函数叫做便利构造函数
     遍历构造函数通常用在对系统的类进行构造函数的扩充时使用
    /*
     遍历构造函数的特点
        1.遍历构造函数通常都是写在extension里面
        2.遍历构造函数init前面需要加载convenience
        3.在遍历构造函数中需要明确的调用self.init()
     */

时间监听的本质

    // 事件监听本质发送消息.但是发送消息是OC的特性
    // 将方法包装成@SEL --> 类中查找方法列表 --> 根据@SEL找到imp指针(函数指针) --> 执行函数
    // 如果swift中将一个函数声明称private,那么该函数不会被添加到方法列表中
    // 如果在private前面加上@objc,那么该方法依然会被添加到方法列表中

重写init

swift中规定:重写控件的init(frame方法)或者init()方法,必须重写init?(coder aDecoder: NSCoder)

modal一个控制器

modal一个控制器,默认之前的控制器被移除,如果不想被移除,需要设置

popoverVc.modalPresentationStyle = .custom

第三课

请求授权的材料

App Key:3102179627
App Secret:c6663f645ea9ee709e7368a13edb36c9
授权回调页:http://www.baidu.com
取消授权回调页:http://www.baidu.com

请求地址
https://api.weibo.com/oauth2/authorize?client_id=3102179627&redirect_uri=http://www.baidu.com

服务器返回的code
code=6a10e36850c396efa921be8a38bc47b8

AFN使用常见错误

status code == 200,但是提示 unacceptable content-type,表示网络访问正常,但是无法对返回数据做反序列化
解决办法:增加 反序列化数据 格式
另外一个常见错误
status code == 405,不支持的网络请求方法,检查 GET / POST 是否写错

SnapKit框架替代Masonry框架

第四课

属性监听器didSet中如果在init的构造函数中监听某个值无效,谨记

巨坑


accout.screen_name = userInfoDict["screen_name"] as? String
accout.avatar_large = userInfoDict["avatar_large"] as? String           
NSKeyedArchiver.archiveRootObject(accout, toFile: UserAccountViewModel.shareInstance.accountPath)
            
UserAccountViewModel.shareInstance.account = accout

swift4.0中字典转模型不要再用kvc,谨记

MVVM的简介

微博中发布时间的处理代码

class func createTimeString(dateString : String) -> String {
        // 1.创建dateFmt对时间进行格式化
        let fmt = NSDateFormatter()
        fmt.dateFormat = "EEE MM dd HH:mm:ss Z yyyy"
        fmt.locale = NSLocale(localeIdentifier: "en")

        // 2.将字符串转成时间
        guard let createDate = fmt.dateFromString(dateString) else {
            return ""
        }

        // 3.获取当前时间
        let nowDate = NSDate()

        // 4.比较两个时间差
        let interval = Int(nowDate.timeIntervalSinceDate(createDate))

        // 5.根据时间差,计算要显示的字符串
        // 5.1.1分钟内:刚刚
        if interval < 60 {
            return "刚刚"
        }

        // 5.2.1小时内:15分钟前
        if interval < 60 * 60 {
            return "\(interval / 60)分钟前"
        }

        // 5.3.1天内:3小时前
        if interval < 60 * 60 * 24 {
            return "\(interval / (60 * 60))小时前"
        }

        let calendar = NSCalendar.currentCalendar()
        // 5.4.昨天: 昨天 03:24
        if calendar.isDateInYesterday(createDate) {

            fmt.dateFormat = "HH:mm"
            return "昨天 \(fmt.stringFromDate(createDate))"
        }

        // 5.5.一年内: 02-23 03:24
        let comps =  calendar.components(.Year, fromDate: createDate, toDate: nowDate, options: [])
        if comps.year < 1 {
            fmt.dateFormat = "MM-dd HH:mm"
            return fmt.stringFromDate(createDate)
        }

        // 5.6.一年后: 2015-2-23 03:23
        if comps.year >= 1 {
            fmt.dateFormat = "yyyy-MM-dd HH:mm"
            return fmt.stringFromDate(createDate)
        }

        return ""
    }

归档 & 解档的复习

归档和解档是用来保存OC对象,OC对象要进行归档和解档的话对象必须遵守NScoding协议,然后实现协议方法

// MARK: - 归档 & 解档
/// 归档 -> 将当前对象归档保存至二进制文件之前被调用
///
/// - parameter aCoder: 编码器
func encodeWithCoder(aCoder: NSCoder) {
    aCoder.encodeObject(access_token, forKey: "access_token")
    aCoder.encodeObject(expiresDate, forKey: "expiresDate")
    aCoder.encodeObject(uid, forKey: "uid")
    aCoder.encodeObject(screen_name, forKey: "screen_name")
    aCoder.encodeObject(avatar_large, forKey: "avatar_large")
}

/// 解档 -> 从二进制文件恢复成对象时调用,与网络的反序列化功能类似
///
/// - parameter aDecoder: 解码器
///
/// - returns: 用户账户对象
required init?(coder aDecoder: NSCoder) {
    access_token = aDecoder.decodeObjectForKey("access_token") as? String
    expiresDate = aDecoder.decodeObjectForKey("expiresDate") as? NSDate
    uid = aDecoder.decodeObjectForKey("uid") as? String
    screen_name = aDecoder.decodeObjectForKey("screen_name") as? String
    avatar_large = aDecoder.decodeObjectForKey("avatar_large") as? String
}
/// 将当前对象保存至沙盒
func saveUserAccount() {
    var path = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).last!
    path = (path as NSString).stringByAppendingPathComponent("account.plist")

    print(path)

    NSKeyedArchiver.archiveRootObject(self, toFile: path)
}

第五课

在新浪项目的视图模型中处理配图数据

    if let picURLDicts = status.pic_urls{
            for picURLDict in picURLDicts{
                guard let picURLString = picURLDict["thumbnail_pic"] else{
                    continue
                }
                picURLs.append(NSURL(string: picURLString)!)
            }
        }

单张配图的展示

因为新浪的返回数据中没有图片的宽高,所以我们要获取单张配图的宽高,需要先缓存图片

计算cellHeight

在开发中我们可以使用自动布局,让cell中的所有空间自动计算高度,只要在tableView中设置

       self.tableView.rowHeight = UITableViewAutomaticDimension
        self.tableView.estimatedRowHeight = 200;
        还需要设置cell最底部的控件距离cell的底部固定间距

也可以在viewModel模型中设置一个cellHeight属性
在tableView中设置

self.tableView.estimatedRowHeight = 200;
如果在tableview中设置估算高度,那么tableview加载的时候会首先加载数据源方法,在数据源方法中会调用uitableviewCell,我们可以在cell中setModel属性计算属性,再保存到模型的cellHeight当中

在项目中集成MJRefresh

在项目开始加载首页时进入下拉加载最新数据
在reloadData后面停止刷新

            self.tableView.reloadData()
            
            self.tableView.mj_header.endRefreshing()
            self.tableView.mj_footer.endRefreshing()

第六课

通知的使用

在Swift3.0以后通知的改变

注册通知

NotificationCenter.default.post(name: NSNotification.Name(rawValue: "AuthSuccessNotification"), object: nil)

监听通知

NotificationCenter.default.addObserver(self, selector:#selector(ViewController.pageJump), name: NSNotification.Name(rawValue: "AuthSuccessNotification"), object: nil)

销毁通知

deinit {
        NotificationCenter.default.removeObserver(self)
}

加载表情的视图模型

15195472525419.png

第七课

图文混排

let attStr = NSAttributedString(string: "陈栐齐", attributes: [NSAttributedStringKey.foregroundColor : UIColor.orange])
        
        let attstr1 = NSAttributedString(string: "陈恒均", attributes: [NSAttributedStringKey.foregroundColor : UIColor.red])
        
        //图文混排
        
        let attachment = NSTextAttachment()
        attachment.image = UIImage(named: "compose_emotion_delete")
        let font = textView.font
        attachment.bounds = CGRect(x: 0, y: -4, width: (font?.lineHeight)!, height: (font?.lineHeight)!)
        
        
        let attrImageStr = NSAttributedString(attachment: attachment)
        
        let attrMStr = NSMutableAttributedString()
        attrMStr.append(attStr)
        attrMStr.append(attrImageStr)
        attrMStr.append(attstr1)
        
        textView.attributedText = attrMStr

AFN常见错误

请求失败-Error Domain=com.alamofire.error.serialization.response Code=-1011 "Request failed: bad request (400)" UserInfo={com.alamofire.serialization.response.error.response=<NSHTTPURLResponse: 0x7cec30d0> { URL: https://api.weibo.com/oauth2/access_token } { status code: 400, headers {

正则表达式

http://www.cnblogs.com/zxin/archive/2013/01/26/2877765.html

let str = "sdadsadsadsad1233122"
        
        let pattern = "^1[3578]\\d{9}$"
        
        guard let regex = try? NSRegularExpression(pattern: pattern, options: []) else{
            return
        }
        
        let results = regex.matches(in: str, options: [], range: NSRange(location: 0, length: str.characters.count))
        
        for result in results {
            print((str as NSString).substring(with: result.range))
            print(result.range)
        }

for循环swift3.0的改变

倒序遍历

for i in (0...10).reversed() {  
    print(i)  
} 
上一篇 下一篇

猜你喜欢

热点阅读