OC中的位枚舉在swift中的替代方案

位移枚舉在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
}

語法報錯為


Snip20190624_7.png

把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下簡單,這里只是作為學習和研究使用亭引。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末绎速,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子焙蚓,更是在濱河造成了極大的恐慌纹冤,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件购公,死亡現(xiàn)場離奇詭異萌京,居然都是意外死亡,警方通過查閱死者的電腦和手機宏浩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門知残,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人比庄,你說我怎么就攤上這事求妹。” “怎么了佳窑?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵制恍,是天一觀的道長。 經(jīng)常有香客問我神凑,道長净神,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮鹃唯,結果婚禮上爱榕,老公的妹妹穿的比我還像新娘。我一直安慰自己俯渤,他們只是感情好呆细,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著八匠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪趴酣。 梳的紋絲不亂的頭發(fā)上梨树,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天,我揣著相機與錄音岖寞,去河邊找鬼抡四。 笑死,一個胖子當著我的面吹牛仗谆,可吹牛的內(nèi)容都是我干的指巡。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼隶垮,長吁一口氣:“原來是場噩夢啊……” “哼藻雪!你這毒婦竟也來了?” 一聲冷哼從身側響起狸吞,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤勉耀,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蹋偏,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體便斥,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年威始,在試婚紗的時候發(fā)現(xiàn)自己被綠了枢纠。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡黎棠,死狀恐怖晋渺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情葫掉,我是刑警寧澤些举,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站俭厚,受9級特大地震影響户魏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一叼丑、第九天 我趴在偏房一處隱蔽的房頂上張望关翎。 院中可真熱鬧,春花似錦鸠信、人聲如沸纵寝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽爽茴。三九已至,卻和暖如春绰垂,著一層夾襖步出監(jiān)牢的瞬間室奏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工劲装, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留胧沫,地道東北人。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓占业,卻偏偏與公主長得像绒怨,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子谦疾,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345