Swift 是面向协议编程 (Protocol Oriented Programming,以下简称 POP) 的。使用非常灵活,扩展性非常强。
项目中用到的Protocol很多,将应用的场景总结一下。(开始时不知其滋味,细细品味后欲罢不能,夸,总之是很好用就是了)
优点:
- 代码复用
- 功能模块清晰
Protocol 作为类型
- 数组中可以包含多种类型的数据
private protocol DBAvailableType {}
extension Bool: DBAvailableType {}
extension String: DBAvailableType {}
extension Int: DBAvailableType {}
extension Int16: DBAvailableType {}
extension Double: DBAvailableType {}
extension NSNull: DBAvailableType {}
var arguments: [DBAvailableType] = []
- 相似但不同的数据模型,给同一UI赋值(数据是协议类型:有时可能用ABtest两种方式获取的数据,为了兼容和复用)。
protocol MapRoute {
var length: UInt { get }
var duration: TimeInterval { get }
}
extension NMARoute: MapRoute {
var length: UInt {
return route.length
}
var duration: TimeInterval {
return route.duration
}
}
extension TPPRoute: MapRoute {
var length: UInt {
return route.length
}
var duration: TimeInterval {
return route.duration
}
}
埋点
虽然有些埋点可以通过hook的方式无侵入地添加,但是有些业务埋点代码被塞进逻辑中无可避免。开始时是直接写在控制器中调用,但是这样会让控制器变得臃肿。后来想到可以用Protocol,总结一下好处:
- 减少控制器的埋点实现代码,在Protocol中定义好方法,并给出方法的默认实现。
- 复用率高,不同地方都要埋点时,遵守协议即可。
- 埋点也可以写在分类中,分散在不同的文件中。 但是复用率就不够高了。
- 打点可以些在父控制器UIViewController中,也可以复用。但会加深代码层级,逻辑变得更加复杂。
- Demo
protocol TPPSubscriptionPromoAnalyticProtocal {
func logCompaignOctPageViewEvent(source: TPPCompaignOctPageViewEvent.Source) //定义方法
}
extension TPPSubscriptionPromoAnalyticProtocal {
//利用extension给出默认实现。
func logCompaignOctPageViewEvent(source: TPPCompaignOctPageViewEvent.Source) {
let event = TPPCompaignOctPageViewEvent(source: source)
AnalyticsManager.log(event: event)
}
}
// 使用时,遵守协议。在需要的地方调用方法即可
class TPPSubscriptionPromoVC: TPPSubscriptionPromoAnalyticProtocal {
}
Protocol 扩展方法和属性
- 为UIButton 或者特定的UIView的类添加放大效果
protocol TPPBigEffectProtocol: class {
func biggerEffect()
}
//为UIButton添加方法效果方法。
extension UIButton: TPPBigEffectProtocol {
func biggerEffect() {
UIView.animate(withDuration: 0.25, animations: {
self.transform = CGAffineTransform.init(scaleX: 1.5, y: 1.5)
}) { (_) in
self.transform = CGAffineTransform.identity
}
}
}
- 获取不同设备横竖屏状态下的有效内容高度(只要遵守了TPPDisplayViewProtocol的类对象都可以直接通过
getViewWidth
方法获取)
protocol TPPDisplayViewProtocol: AnyObject {
func getViewWidth() -> CGFloat
}
extension TPPDisplayViewProtocol {
func getViewWidth() -> CGFloat {
let orientation = UIApplication.shared.statusBarOrientation
if orientation == .portrait || orientation == .portraitUpsideDown {
return UIScreen.main.bounds.width
} else {
if iPhoneXSeries {
return (UIScreen.main.bounds.width - 88)
} else {
return UIScreen.main.bounds.width
}
}
}
}
- 为一个tableViewCell设置一个唯一标志符,通常让cell 遵循一个协议,在协议里面定义一个uniqueIdentifier。用自己的类名作为唯一标识符。
// 1. 定义一个协议
protocol CellProtocol: class {
static var uniqueIdentifier: String {get}
}
// 2. 协议扩展来实现属性
extension CellProtocol {
static var uniqueIdentifier: String {
return String(describing: type(of: self)).components(separatedBy: ".").first!
}
}
// 3.调用
// 先遵守协议
class TPPReviewCell: UITableViewCell, CellProtocol {
}
// 在用到这个cell的cellForRow里面
let cell = tableView.dequeueReusableCell(withIdentifier: TPPReviewCell.uniqueIdentifier) as! TPPReviewCell
Protocol 和Delegate的配合使用
- 定义协议方法
protocol DropDownMenuDelegate: NSObjectProtocol {
func menuView(_ menuView: DropdownMenuView, didSelectColumnAt index: Int)
}
- 设置delegate属性,调用
DropdownMenuView.swift
weak open var delegate: DropDownMenuDelegate?
if let delegate = delegate {
delegate.menuView(self, didSelectColumnAt: index)
}
- 遵守协议,实现协议方法
TPPTruckDealerDetailController.swift
lazy private var dropMenuView = DropdownMenuView()
dropMenuView.delegate = self
extension TPPTruckDealerDetailController: DropDownMenuDelegate {
func menuView(_ menuView: DropdownMenuView, didSelectColumnAt index: Int) {
eventRecord(outcome: "Sort")
}
}
网友评论