直播项目笔记(四)

心跳包 + 图文混排 + Core Graphics

Socket 服务器加入心跳包

Timer 和 Runloop

  • Timer只负责计时,Timer所绑定的动作,是由Runloop来执行的,Runloop运行的时候需要指定运行模式,一个timer同一时间只可以注册到一个runloop中,但是可以添加到这个runloop的多个运行模式中

  • 两个创建Timer的区别

test1 //计时器会在当前循环最后进行 先输出haha才开始计数

override func viewDidLoad() {
    super.viewDidLoad()
       
    // 创建 timer
    timer = Timer(timeInterval: 1, target: self, selector: #selector(test), userInfo: nil, repeats: true)
    /*
    创建一个 timer 加入到当前 runloop 默认模式
    timer = Timer(timeInterval: 1, target: self, selector: #selector(test), userInfo: nil, repeats: true)
    */
       
    // 将 timer 加入到 Runloop 中
    RunLoop.current.add(timer, forMode: .commonModes)
    print("haha")
}
        
@objc func test() {
    count += 1
    print("\(count)")
}
test2 //计时器手动开始执行 fire() 先开始第一次计数再输出haha
override func viewDidLoad() {
  super.viewDidLoad()
  
  timer = Timer(fireAt: Date(), interval: 1, target: self, selector: #selector(test), userInfo: nil, repeats: true)
  // 将 timer 加入到 Runloop 中
  RunLoop.current.add(timer, forMode: .commonModes)
  timer.fire()
  print("哈哈")
}
   
@objc func test() {
  count += 1
  print("\(count)")
}

添加聊天内容

正则表达式

在编写处理字符串的程序或网页时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码

  • 常用元字符
\ba\w*\b匹配以字母a开头的单词——先是某个单词开始处(\b),然后是字母a,然后是任意数量的字母或数字(\w*),最后是单词结束处(\b)。
\d+匹配1个或更多连续的数字。这里的+是和*类似的元字符,不同的是*匹配重复任意次(可能是0次),而+则匹配重复1次或更多次。
\b\w{6}\b 匹配刚好6个字符的单词。
代码 说明
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线或汉字
\s 匹配任意的空白符
\d 匹配数字
^ 匹配字符串的开始
$ 匹配字符串的结束
一个网站如果要求你填写的QQ号必须为5位到12位数字时,可以使用:^\d{5,12}$
  • 字符转义

如果你想查找元字符本身的话,比如你查找.,或者*,就出现了问题:你没办法指定它们,因为它们会被解释成别的意思。这时你就得使用\来取消这些字符的特殊意义。因此,你应该使用\.和\*。当然,要查找\本身,你也得用\
在swift中 转义字符是 \\

  • 重复
代码/语法 说明
* 重复零次或更多次
+ 重复一次或更多次
重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次
  • 字符类 [ ]

[aeiou]匹配任何一个英文元音字母
[.?!]匹配标点符号(.或?或!)

  • 分歧条件 |

\d{5}-\d{4}|\d{5}这个表达式用于匹配美国的邮政编码。美国邮编的规则是5位数字,或者用连字号间隔的9位数字。之所以要给出这个例子是因为它能说明一个问题:使用分枝条件时,要注意各个条件的顺序。如果你把它改成\d{5}|\d{5}-\d{4}的话,那么就只会匹配5位的邮编(以及9位邮编的前5位)。原因是匹配分枝条件时,将会从左到右地测试每个条件,如果满足了某个分枝的话,就不会去再管其它的条件了

富文本(NSAttributedString)

直播项目笔记(四)_第1张图片
image
  • 给字符串特定字符换颜色
let str = "小明:哈哈哈哈"
label1.text = str
        
let attr = NSMutableAttributedString(string: str)
// NSAttributedStringKey里还有更多可修改的属性
attr.addAttributes([NSAttributedStringKey.foregroundColor: UIColor.orange], range: NSRange(location: 0, length: 2))
label2.attributedText = attr
  • 图文混排
let str = "小明:[鄙视]你怎么这样[呲牙]"
label1.text = str
   
let attr = NSMutableAttributedString(string: str)
// 正则表达式 匹配表情
let pattern = "\\[.*?\\]"
let regex = try! NSRegularExpression(pattern: pattern, options: [])
let results = regex.matches(in: str, options: [], range: NSRange(location: 0, length: str.count))
// 获取表情的结果 从后往前匹配 避免打乱前面字符串的range
for i in (0..

礼物动画展示

Core Graphics

1. 什么是Core Graphics

Core Graphics Framework是一套基于C的API框架,使用了Quartz作为绘图引擎。它提供了低级别、轻量级、高保真度的2D渲染。该框架可以用于基于路径的绘图、变换、颜色管理、脱屏渲染,模板、渐变、遮蔽、图像数据管理、图像的创建、遮罩以及PDF文档的创建、显示和分析

2. 绘图的一般步骤

(1)获取绘图上下文
(2)创建并设置路径
(3)将路径添加到上下文
(4)设置上下文状态(如笔触颜色、宽度、填充色等等)
(5)绘制路径

3. 绘制图形
  • http://www.hangge.com/blog/cache/detail_1437.html
  • 绘制直线
override func draw(_ rect: CGRect) {
   super.draw(rect)
   let context = UIGraphicsGetCurrentContext() // 获取上下文 创建画布
   let path = CGMutablePath() // 创建路径
   path.move(to: CGPoint(x: 20, y: 50)) // 移动到指定位置(设置路径起点)
   path.addLine(to: CGPoint(x: 20, y: 100)) // 绘制直线(从起始位置开始)
   context?.addPath(path) // 把路径添加到上下文(画布)中
   // Core Graphics中还提供了很多预先设置好的路径
   // CGContext.add()
   
   // 设置图形上下文状态属性
   context?.setStrokeColor(UIColor.blue.cgColor) // 设置笔触颜色
   
   // 阴影 虚线 填充色 顶点 连接点 ...
   
   // 填充类型中可以选择只绘制边框、只填充、同时绘制边框和填充内部区域、奇偶规则填充等
   context?.setTextDrawingMode(.stroke) // 填充类型
   // 绘制路径
   context?.strokePath()
   // OC的ARC机制并不会对它进行内存管理,但是Swift对它自动进行了,所以在Swift中不需要写这个代码  CGPathRelease(path)
}

Keyframe动画

Keyframe动画可以让我们有效的拆分由若干段动画连接而成的复杂动画,可以较为精准的定义每段动画的起始点及持续时间,并且在代码组织方面也非常清晰

UIView.animateWithDuration(1, animations: {  
    view.center.x += 200.0  
}, completion: { _ in  
    UIView.animateWithDuration(1, animations: {  
        view.center.y += 100.0  
    }, completion: { _ in  
        UIView.animateWithDuration(1, animations: {  
            view.center.x -= 200.0  
        }, completion: { _ in  
            UIView.animateWithDuration(1, animations: {  
                view.center.y -= 100.0  
            }, completion: nil)  
        })  
    })  
})

// or

UIView.animateKeyframesWithDuration(2, delay: 0, options: [], animations: {  
    // relativeDuration 是总动画时长的百分比
    UIView.addKeyframeWithRelativeStartTime(0, relativeDuration: 0.25, animations: {  
            view.center.x += 200.0  
        })  
        UIView.addKeyframeWithRelativeStartTime(0.25, relativeDuration: 0.25, animations: {  
            view.center.y += 100.0  
        })  
        UIView.addKeyframeWithRelativeStartTime(0.5, relativeDuration: 0.25, animations: {  
            view.center.x -= 200.0  
        })  
        UIView.addKeyframeWithRelativeStartTime(0.75, relativeDuration: 0.25, animations: {  
            view.center.y -= 100.0  
        })  
}, completion: nil)
  • 礼物连击动画
UIView.animateKeyframes(withDuration: 0.25, delay: 0, options: [], animations: {
    UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 0.5, animations: {
        self.transform = CGAffineTransform(scaleX: 3.0, y: 3.0)
    })
      
    UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5, animations: {
        self.transform = CGAffineTransform(scaleX: 0.7, y: 0.7)
    })
}, completion: { isFinished in
    UIView.animate(withDuration: 0.25, delay: 0, usingSpringWithDamping: 0.3, initialSpringVelocity: 10, options: [], animations: {
        self.transform = CGAffineTransform.identity
    }, completion: { (isFinished) in
        complection()
    })
})

取消延迟执行函数

// 取消一个对象在当前Run Loop中的所有未执行的
NSObject.cancelPreviousPerformRequests(withTarget: self)
self.perform(#selector(self.test), with: self, afterDelay: 3.0)
// 调用取消执行函数后 test方法不会执行
NSObject.cancelPreviousPerformRequests(withTarget: self)

你可能感兴趣的:(直播项目笔记(四))