位移枚舉在OC中非常常見也是非常方便運用的费就,舉個例子SD_image中的SDWebImageOptions
1> NS_OPTIONS與位運算
NS_OPTIONS用來定義位移相關操作的枚舉值,當一個枚舉變量需要攜帶多種值的時候就需要蔑水,我們可以參考UIKit.Framework的頭文件梳玫,可以看到大量的枚舉定義。例如在SDWebImage下面就會接觸到SDWebImageOptions枚舉值:
typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
SDWebImageRetryFailed = 1 << 0,
SDWebImageLowPriority = 1 << 1,
SDWebImageCacheMemoryOnly = 1 << 2,
SDWebImageProgressiveDownload = 1 << 3,
SDWebImageRefreshCached = 1 << 4,
SDWebImageContinueInBackground = 1 << 5,
SDWebImageHandleCookies = 1 << 6,
SDWebImageAllowInvalidSSLCertificates = 1 << 7,
SDWebImageHighPriority = 1 << 8,
SDWebImageDelayPlaceholder = 1 << 9,
SDWebImageTransformAnimatedImage = 1 << 10,
SDWebImageAvoidAutoSetImage = 1 << 11,
SDWebImageScaleDownLargeImages = 1 << 12
};
找了一篇位運算基礎 https://baike.baidu.com/item/位運算/6888804
================分界線================
然而治宣,在swift中使用位枚舉的時候發(fā)現(xiàn)swift本身不支持原來的語法急侥,我們先嘗試原來的寫作方法:
public enum Corner {
case topLeft = 1 << 1
case topRight = 1 << 2
case bottomLeft = 1 << 3
case bottomRight = 1 << 4
// case all
}
語法報錯為
把Corner改為Int類型仍然解決不了問題,(enum Corner: Int).
swift 的枚舉不支持運算值侮邀,只支持儲存值坏怪,那試試吧位移值的具體值計算出來
public enum Corner: Int {
case topLeft = 2
case topRight = 4
case bottomLeft = 8
case bottomRight = 16
// case all
}
雖然不報錯了,但是這種寫法如果枚舉值很多的話绊茧,他們之間的關系不夠直觀,既那然枚舉值不能是計算值铝宵,那么我們給枚舉添加一個值的屬性。事例代碼如下:
public enum RectCorner: RectCornersValue {
case topLeft
case topRight
case bottomLeft
case bottomRight
case all
}
extension RectCorner {
fileprivate var value: Int {
switch self {
case .topLeft: return 1 << 0
case .topRight: return 1 << 1
case .bottomLeft: return 1 << 2
case .bottomRight: return 1 << 3
case .all:
return RectCorner.topLeft.value | RectCorner.topRight.value | RectCorner.bottomLeft.value | RectCorner.bottomRight.value
}
}
}
我們先忽略RectCornersValue,給枚舉RectCorner寫了個私有的value屬性鹏秋,也就是位移枚舉的計算值尊蚁,
使枚舉能使用位運算,需要重載運算符‘|’
infix operator | : precedence
precedencegroup precedence { associativity: left }
重載運算符‘|’后侣夷,運算值為Int類型横朋,也就是意味著,方法接受枚舉類型同時也可能是枚舉位運算的Int類型百拓,這里我們用協(xié)議擴展約束類型
public protocol RectCornersValue {}
extension Int: RectCornersValue {}
同時 enum RectCorner: RectCornersValue 枚舉也要遵循協(xié)議約束琴锭,這樣方法參數(shù)類型RectCornersValue支持枚舉和枚舉的位運算值。
下面舉個例子給view的任意角添加圓角衙传,方法聲明如下:
func cornerSet (_ radius: CGFloat, corners: RectCornersValue) { }
當角的參數(shù)為組合枚舉的時候如何檢測組合的元素决帖,這里需要位運算的知識,這里例子如下:
extension RectCornersValue {
fileprivate func isContains(_ objEnum: RectCorner) -> Bool {
if (self as? Int) != nil {
let value = self as! Int
return value & objEnum.value != 0
} else {
let value = (self as? RectCorner)?.value ?? 0
return value & objEnum.value != 0
}
}
}
完整的代碼實例為
import Foundation
infix operator | : precedence
precedencegroup precedence { associativity: left }
public protocol RectCornersValue {}
extension Int: RectCornersValue {}
/// RectCorner
///
/// - topLeft: topLeft
/// - topRight: topRight
/// - bottomLeft: bottomLeft
/// - bottomRight: bottomRight
/// - all: all
public enum RectCorner: RectCornersValue {
case topLeft
case topRight
case bottomLeft
case bottomRight
case all
}
extension RectCorner {
fileprivate var value: Int {
switch self {
case .topLeft: return 1 << 0
case .topRight: return 1 << 1
case .bottomLeft: return 1 << 2
case .bottomRight: return 1 << 3
case .all:
return RectCorner.topLeft.value | RectCorner.topRight.value | RectCorner.bottomLeft.value | RectCorner.bottomRight.value
}
}
static func | (left: RectCornersValue , right: RectCorner) -> RectCornersValue {
if ((left as? Int) != nil) {
let leftValue: Int = (left as! Int)
return leftValue | right.value
} else {
let leftValue: RectCorner = (left as! RectCorner)
return leftValue.value | right.value
}
}
}
extension RectCornersValue {
fileprivate func isContains(_ objEnum: RectCorner) -> Bool {
if (self as? Int) != nil {
let value = self as! Int
return value & objEnum.value != 0
} else {
let value = (self as? RectCorner)?.value ?? 0
return value & objEnum.value != 0
}
}
}
extension UIView {
/// view任意圓角弧度設置
///
/// - Parameters:
/// - radius: 弧度半徑
/// - corners: 角 RectCorner蓖捶,支持位枚舉
func cornerSet (_ radius: CGFloat, corners: RectCornersValue) {
self.setNeedsLayout()
self.layoutIfNeeded()
var radius = radius
let pathRef = CGMutablePath()
let bounds: CGRect = self.bounds
let allowdMaxRadius = min(bounds.size.width, bounds.size.height)/2.0
if radius > allowdMaxRadius { radius = allowdMaxRadius }
let leftMiddle = CGPoint(x: bounds.minX, y: bounds.midY)
let topLeft = CGPoint(x: bounds.minX, y: bounds.minY)
let topRight = CGPoint(x: bounds.maxX, y: bounds.minY)
let bottomLeft = CGPoint(x: bounds.minX, y: bounds.maxY)
let bottomRight = CGPoint(x: bounds.maxX, y: bounds.maxY)
let topMiddle = CGPoint(x: bounds.midX, y: bounds.minY)
let bottomMiddle = CGPoint(x: bounds.midX, y: bounds.maxY)
let rightMiddle = CGPoint(x: bounds.maxX, y: bounds.midY)
func drawLine(p1: CGPoint, p2: CGPoint, _ corner: RectCorner) {
if corners.isContains(corner) {
pathRef.addArc(tangent1End: p1,
tangent2End: p2,
radius: radius,
transform: .identity)
} else {
pathRef.addLine(to: p1)
pathRef.addLine(to: p2)
}
}
pathRef.move(to: leftMiddle)
drawLine(p1: topLeft, p2: topMiddle, .topLeft)
drawLine(p1: topRight, p2: rightMiddle, .topRight)
drawLine(p1: bottomRight, p2: bottomMiddle, .bottomLeft)
drawLine(p1: bottomLeft, p2: leftMiddle, .bottomRight)
let layer = CAShapeLayer()
layer.path = pathRef
self.layer.mask = layer
}
}
//用法: label.cornerSet (10.0, corners:RectCornersValue.topLeft | RectCornersValue.topRight)
總結:所運用知識有位運算地回,枚舉,運算符重載腺阳,協(xié)議及協(xié)議約束等
總體來說落君,swift下的位枚舉運用沒有OC下簡單,這里只是作為學習和研究使用亭引。