Làm thế nào để tôi có được số đếm của một enum Swift?


Câu trả lời:


172

Kể từ Swift 4.2 (Xcode 10), bạn có thể khai báo sự phù hợp với CaseIterablegiao thức, điều này hoạt động cho tất cả các liệt kê mà không có giá trị liên quan:

enum Stuff: CaseIterable {
    case first
    case second
    case third
    case forth
}

Số lượng các trường hợp bây giờ chỉ đơn giản là thu được với

print(Stuff.allCases.count) // 4

Để biết thêm thông tin, xem


1
Trong phiên bản mới nhất của swift, lỗi ném của nó "Loại 'DAFFlow' không tuân thủ giao thức 'RawRepftimeable'". Tại sao nó buộc tôi phải theo điều đó? Bất kỳ ý tưởng?
Satyam

@Satyam: DAFFlow là gì?
Martin R

xin lỗi tôi đã quên đề cập rằng "DAFFlow 'là một enum đơn giản không được thừa hưởng từ bất kỳ giao thức nào khác.
Satyam

1
Đây là giải pháp tốt nhất, nhưng chỉ cần rõ ràng - các nhà phát triển của Apple sẽ chỉ thực sự có thể bắt đầu sử dụng Xcode 10 này (và do đó Swift 4.2) ra khỏi phiên bản beta (rất có thể vào khoảng ngày 14 tháng 9 năm 2018).
JosephH

1
@DaniSpringer: Bạn sẽ tìm thấy thông tin chi tiết tại github.com/apple/swift-evolution/blob/master/proposeals/ trên . Nhưng thông thường, bạn không cần loại đó một cách rõ ràng, do suy luận kiểu tự động của trình biên dịch.
Martin R

143

Tôi có một bài đăng trên blog chi tiết hơn về vấn đề này, nhưng miễn là kiểu thô của enum của bạn là một số nguyên, bạn có thể thêm số đếm theo cách này:

enum Reindeer: Int {
    case Dasher, Dancer, Prancer, Vixen, Comet, Cupid, Donner, Blitzen
    case Rudolph

    static let count: Int = {
        var max: Int = 0
        while let _ = Reindeer(rawValue: max) { max += 1 }
        return max
    }()
}

16
Mặc dù tốt vì bạn không cần mã hóa một giá trị, nhưng điều này sẽ khởi tạo mọi giá trị enum mỗi khi nó được gọi. Đó là O (n) thay vì O (1). :(
Chỉ huy mã

4
Đây là một giải pháp tốt cho Int. Tôi thích một sửa đổi nhỏ. Biến thuộc tính đếm tĩnh thành một phương thức tĩnh CountCase () và gán nó cho caseCount hằng tĩnh, lười biếng và cải thiện hiệu suất với các cuộc gọi lặp lại.
Tom Pelaia

2
@ShamsAhmed: Chuyển đổi var được tính thành tĩnh.
Nate Cook

3
Điều gì nếu bạn bỏ lỡ một số giá trị trong enum? ví dụ case A=1, B=3?
Sasho

2
Có 2 giả định bên cạnh việc enumcó một Intgiá trị thô mà bạn quên đề cập: Swift enum với giá trị thô Int không phải bắt đầu từ 0 (mặc dù đó là hành vi mặc định) và giá trị thô của chúng có thể tùy ý, chúng không có tăng lên 1 (mặc dù đó là hành vi mặc định).
Dávid Pásztor

90

Cập nhật Xcode 10

Thông qua CaseIterablegiao thức trong enum, nó cung cấp một thuộc tính tĩnh allCaseschứa tất cả các trường hợp enum là a Collection. Chỉ cần sử dụng counttài sản của nó để biết có bao nhiêu trường hợp enum có.

Xem câu trả lời của Martin để biết ví dụ (và nêu lên câu trả lời của anh ấy thay vì của tôi)


Cảnh báo : phương pháp bên dưới dường như không hoạt động nữa.

Tôi không biết về bất kỳ phương pháp chung nào để đếm số trường hợp enum. Tuy nhiên, tôi nhận thấy rằng thuộc hashValuetính của các trường hợp enum là tăng dần, bắt đầu từ 0 và với thứ tự được xác định theo thứ tự các trường hợp được khai báo. Vì vậy, hàm băm của enum cuối cùng cộng với một số tương ứng với số lượng các trường hợp.

Ví dụ với enum này:

enum Test {
    case ONE
    case TWO
    case THREE
    case FOUR

    static var count: Int { return Test.FOUR.hashValue + 1}
}

count trả về 4.

Tôi không thể nói nếu đó là một quy tắc hoặc nếu nó sẽ thay đổi trong tương lai, vì vậy hãy tự chịu rủi ro khi sử dụng :)


48
Sống theo tính năng không có giấy tờ, chết bởi tính năng không có giấy tờ. Tôi thích nó!
Nate Cook

9
Chúng ta không nên thực sự dựa vào hashValuesnhững điều này; tất cả những gì chúng ta biết là đó là một số giá trị duy nhất ngẫu nhiên - có thể thay đổi rất dễ dàng trong tương lai tùy thuộc vào một số chi tiết triển khai trình biên dịch; nhưng nhìn chung, việc thiếu chức năng đếm tích hợp là đáng lo ngại.
Zorayr

16
Nếu bạn không nhớ cài đặt rõ ràng case ONE = 0, thì bạn có thể thay thế hashValuebằng rawValue.
Kevin Qi

3
mối quan tâm ở đây là việc sử dụng một tài sản không có giấy tờ của hashValue, vì vậy đề xuất của tôi là sử dụng một tài sản được ghi lại của rawValue.
Kevin Qi

7
Bạn đã mã hóa thực tế rằng hằng số là giá trị cao nhất, Tốt hơn và an toàn hơn khi chỉ sử dụng một cái gì đó như static var count = 4thay vì để số phận của bạn trong số phận của các triển khai trong tương lai của Swift
Dale

72

Tôi xác định một giao thức có thể sử dụng lại, tự động thực hiện đếm trường hợp dựa trên cách tiếp cận được đăng bởi Nate Cook.

protocol CaseCountable {
    static var caseCount: Int { get }
}

extension CaseCountable where Self: RawRepresentable, Self.RawValue == Int {
    internal static var caseCount: Int {
        var count = 0
        while let _ = Self(rawValue: count) {
            count += 1
        }
        return count
    }
}

Sau đó, tôi có thể sử dụng lại giao thức này ví dụ như sau:

enum Planet : Int, CaseCountable {
    case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}
//..
print(Planet.caseCount)

1
Đẹp và thanh lịch, nên là câu trả lời được chấp nhận IMHO
shannoga

1
có lẽ nó tốt hơn để thay đổi count++để count+=1từ ++ký hiệu sẽ được loại bỏ trong Swift 3
Aladin

1
không thể làm điều tương tự chỉ với static var caseCount: Int { get }? Tại sao cần static func?
pxpgraphics

Điều gì nếu bạn bỏ lỡ một số giá trị trong enum? ví dụ case A=1, B=3?
Sasho

1
@Sasho, sau đó nó sẽ không hoạt động. Điều này đòi hỏi các trường hợp của bạn bắt đầu tại 0và không có khoảng trống.
NRitH

35

Tạo mảng allValues ​​tĩnh như trong câu trả lời này

enum ProductCategory : String {
     case Washers = "washers", Dryers = "dryers", Toasters = "toasters"

     static let allValues = [Washers, Dryers, Toasters]
}

...

let count = ProductCategory.allValues.count

Điều này cũng hữu ích khi bạn muốn liệt kê các giá trị và hoạt động cho tất cả các loại Enum


Mặc dù không thanh lịch như giải pháp mở rộng và rất thủ công, tôi tin rằng đây là cách hữu ích nhất vì nó cung cấp nhiều hơn số lượng. Nó cung cấp cho bạn thứ tự các giá trị và một danh sách tất cả các giá trị.
Nader Eloshaiker

2
Bạn cũng có thể thêm số đếm vào enum bằng cách làm static let count = allValues.count. Sau đó, bạn có thể làm cho allValuesriêng tư nếu muốn.
ThomasW

15

Nếu việc triển khai không có bất cứ điều gì chống lại việc sử dụng số nguyên Countenum , bạn có thể thêm một giá trị thành viên bổ sung được gọi để thể hiện số lượng thành viên trong enum - xem ví dụ bên dưới:

enum TableViewSections : Int {
  case Watchlist
  case AddButton
  case Count
}

Bây giờ bạn có thể nhận được số lượng thành viên trong enum bằng cách gọi, TableViewSections.Count.rawValuesẽ trả về 2 cho ví dụ trên.

Khi bạn xử lý enum trong câu lệnh chuyển đổi, hãy đảm bảo đưa ra một lỗi xác nhận khi gặp Countthành viên mà bạn không mong đợi:

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  let currentSection: TableViewSections = TableViewSections.init(rawValue:section)!
  switch(currentSection) {
  case .Watchlist:
    return watchlist.count
  case .AddButton:
    return 1
  case .Count:
    assert(false, "Invalid table view section!")
  }
}

Tôi thích giải pháp đó vì nó tự động thay đổi số đếm khi thêm nhiều giá trị enum. Tuy nhiên, hãy nhớ rằng điều này chỉ hoạt động khi các giá trị thô của enum bắt đầu bằng 0.
tham gia

2
Đồng ý, có hai hạn chế: phải là số nguyên enum và phải bắt đầu từ 0 và tiếp tục tăng dần.
Zorayr

3
Tôi nghĩ rằng toàn bộ quan điểm mạnh mẽ hơn của Swift là chúng ta sẽ không phải sử dụng cùng một bản hack mà chúng ta đã sử dụng trong Objective-C: /
pkamb

14

Loại chức năng này có thể trả về số đếm của enum của bạn.

Swift 2 :

func enumCount<T: Hashable>(_: T.Type) -> Int {
    var i = 1
    while (withUnsafePointer(&i) { UnsafePointer<T>($0).memory }).hashValue != 0 {
        i += 1
    }
    return i
}

Swift 3 :

func enumCount<T: Hashable>(_: T.Type) -> Int {
   var i = 1
   while (withUnsafePointer(to: &i, {
      return $0.withMemoryRebound(to: T.self, capacity: 1, { return $0.pointee })
   }).hashValue != 0) {
      i += 1
   }
      return i
   }

3
Điều này không còn hiệu quả với Swift 3. Cố gắng thực hiện việc triển khai đúng cách, nhưng sắp hết
Cody Winton

Đây sẽ là rất unfun để gỡ lỗi nếu địa chỉ bộ nhớ ngay lập tức tiếp giáp với cuối enumcũng Hashable cùng loại.
NRitH

10

Chuỗi Enum với Index

enum eEventTabType : String {
    case Search     = "SEARCH"
    case Inbox      = "INBOX"
    case Accepted   = "ACCEPTED"
    case Saved      = "SAVED"
    case Declined   = "DECLINED"
    case Organized  = "ORGANIZED"

    static let allValues = [Search, Inbox, Accepted, Saved, Declined, Organized]
    var index : Int {
       return eEventTabType.allValues.indexOf(self)!
    }
}

đếm : eEventTabType.allValues.count

mục lục : objeEventTabType.index

Thưởng thức :)


10

Oh hey mọi người, những gì về bài kiểm tra đơn vị?

func testEnumCountIsEqualToNumberOfItemsInEnum() {

    var max: Int = 0
    while let _ = Test(rawValue: max) { max += 1 }

    XCTAssert(max == Test.count)
}

Điều này kết hợp với giải pháp của Antonio:

enum Test {

    case one
    case two
    case three
    case four

    static var count: Int { return Test.four.hashValue + 1}
}

trong mã chính cung cấp cho bạn O (1) cộng với bạn nhận được một bài kiểm tra thất bại nếu ai đó thêm trường hợp enum fivevà không cập nhật việc thực hiện count.


7

Hàm này dựa trên 2 hành vi hiện tại không có giấy tờ (Swift 1.1) enum:

  • Bố trí bộ nhớ của enumchỉ là một chỉ số của case. Nếu số trường hợp là từ 2 đến 256, thì đó là UInt8.
  • Nếu enumbit được đúc từ chỉ mục trường hợp không hợp lệ , hashValuethì đó là0

Vì vậy, sử dụng có nguy cơ của riêng bạn :)

func enumCaseCount<T:Hashable>(t:T.Type) -> Int {
    switch sizeof(t) {
    case 0:
        return 1
    case 1:
        for i in 2..<256 {
            if unsafeBitCast(UInt8(i), t).hashValue == 0 {
                return i
            }
        }
        return 256
    case 2:
        for i in 257..<65536 {
            if unsafeBitCast(UInt16(i), t).hashValue == 0 {
                return i
            }
        }
        return 65536
    default:
        fatalError("too many")
    }
}

Sử dụng:

enum Foo:String {
    case C000 = "foo"
    case C001 = "bar"
    case C002 = "baz"
}
enumCaseCount(Foo) // -> 3

Trong bản phát hành và ứng dụng adhoc sẽ CRASH
HotJard

Điều này không hoạt động trong trình giả lập nhưng không phải trên một thiết bị 64 bit thực sự.
Daniel Nord

5

Tôi đã viết một phần mở rộng đơn giản cung cấp cho tất cả các enum trong đó giá trị thô là số nguyên một thuộc counttính:

extension RawRepresentable where RawValue: IntegerType {
    static var count: Int {
        var i: RawValue = 0
        while let _ = Self(rawValue: i) {
            i = i.successor()
        }
        return Int(i.toIntMax())
    }
}

Thật không may, nó mang lại cho counttài sản OptionSetTypenơi nó không hoạt động chính xác, vì vậy đây là một phiên bản khác yêu cầu tuân thủ rõ ràng với CaseCountablegiao thức cho bất kỳ trường hợp nào bạn muốn tính:

protocol CaseCountable: RawRepresentable {}
extension CaseCountable where RawValue: IntegerType {
    static var count: Int {
        var i: RawValue = 0
        while let _ = Self(rawValue: i) {
            i = i.successor()
        }
        return Int(i.toIntMax())
    }
}

Nó rất giống với cách tiếp cận được đăng bởi Tom Pelaia, nhưng hoạt động với tất cả các loại số nguyên.


4

Tất nhiên, nó không động nhưng với nhiều mục đích sử dụng, bạn có thể nhận được bằng một var tĩnh được thêm vào Enum của bạn

static var count: Int{ return 7 }

và sau đó sử dụng nó như là EnumName.count


3
enum EnumNameType: Int {
    case first
    case second
    case third

    static var count: Int { return EnumNameType.third.rawValue + 1 }
}

print(EnumNameType.count) //3

HOẶC LÀ

enum EnumNameType: Int {
    case first
    case second
    case third
    case count
}

print(EnumNameType.count.rawValue) //3

* Trên Swift 4.2 (Xcode 10) có thể sử dụng:

enum EnumNameType: CaseIterable {
    case first
    case second
    case third
}

print(EnumNameType.allCases.count) //3

2

Đối với trường hợp sử dụng của tôi, trong một cơ sở mã nơi nhiều người có thể thêm khóa vào enum và tất cả các trường hợp này đều có sẵn trong thuộc tính allKeys, điều quan trọng là allKeys phải được xác thực đối với các khóa trong enum. Điều này là để tránh ai đó quên thêm khóa của họ vào danh sách tất cả các khóa.Khớp số đếm của mảng allKeys (lần đầu tiên được tạo thành một tập hợp để tránh các bản sao) so với số lượng khóa trong enum đảm bảo rằng tất cả chúng đều có mặt.

Một số câu trả lời ở trên chỉ ra cách để đạt được điều này trong Swift 2 nhưng không có câu trả lời nào trong Swift 3 . Đây là phiên bản định dạng Swift 3 :

static func enumCount<T: Hashable>(_ t: T.Type) -> Int {
    var i = 1
    while (withUnsafePointer(to: &i) {
      $0.withMemoryRebound(to:t.self, capacity:1) { $0.pointee.hashValue != 0 }
    }) {
      i += 1
    }
    return i
}

static var allKeys: [YourEnumTypeHere] {
    var enumSize = enumCount(YourEnumTypeHere.self)

    let keys: Set<YourEnumTypeHere> = [.all, .your, .cases, .here]
    guard keys.count == enumSize else {
       fatalError("Missmatch between allKeys(\(keys.count)) and actual keys(\(enumSize)) in enum.")
    }
    return Array(keys)
}

Tùy thuộc vào trường hợp sử dụng của bạn, bạn có thể muốn chạy thử nghiệm trong quá trình phát triển để tránh chi phí sử dụng allKeys trên mỗi yêu cầu


2

Tại sao bạn làm cho nó quá phức tạp? Bộ đếm SIMPLEST của Int enum là thêm:

case Count

Đến cuối cùng. Và ... viola - bây giờ bạn có số đếm - nhanh chóng và đơn giản


1
Điều này a) thêm trường hợp enum ngoại lai và b) sẽ không hoạt động nếu loại thô của enum là bất cứ thứ gì khác ngoài Int.
Robert Atkins

Đây thực sự không phải là một câu trả lời tồi. Tuy nhiên, giống như câu trả lời của @Tom Pelaia ở trên, nó yêu cầu các giá trị thô bắt đầu 0và không có khoảng trống trong chuỗi.
NRitH

1

Nếu bạn không muốn căn cứ mã của mình vào enum cuối cùng, bạn có thể tạo hàm này bên trong enum của mình.

func getNumberOfItems() -> Int {
    var i:Int = 0
    var exit:Bool = false
    while !exit {
        if let menuIndex = MenuIndex(rawValue: i) {
            i++
        }else{
            exit = true
        }
    }
    return i
}

1

Một Swift 3 phiên bản làm việc với Intloại enums:

protocol CaseCountable: RawRepresentable {}
extension CaseCountable where RawValue == Int {
    static var count: RawValue {
        var i: RawValue = 0
        while let _ = Self(rawValue: i) { i += 1 }
        return i
    }
}

Tín dụng: Dựa trên các câu trả lời của bzz và Nate Cook.

Chung IntegerType(trong Swift 3 được đổi tên thành Integer) không được hỗ trợ, vì đây là loại chung bị phân mảnh nặng nề, thiếu rất nhiều chức năng.successorkhông có sẵn với Swift 3 nữa.

Xin lưu ý rằng nhận xét từ Code Commander đến Nate Cooks vẫn còn hiệu lực:

Mặc dù tốt vì bạn không cần mã hóa một giá trị, nhưng điều này sẽ khởi tạo mọi giá trị enum mỗi khi nó được gọi. Đó là O (n) thay vì O (1).

Theo như tôi biết hiện tại không có cách giải quyết nào khi sử dụng phần mở rộng giao thức này (và không triển khai trong mỗi enum như Nate Cook đã làm) do các thuộc tính lưu trữ tĩnh không được hỗ trợ trong các loại chung.

Dù sao, đối với các enum nhỏ thì điều này không có vấn đề gì. Một trường hợp điển hình sử dụng sẽ là section.countcho UITableViewsnhư đã đề cập bởi Zorayr.


1

Mở rộng câu trả lời của Matthieu Riegler, đây là một giải pháp cho Swift 3 không yêu cầu sử dụng thuốc generic và có thể dễ dàng được gọi bằng cách sử dụng loại enum với EnumType.elementsCount:

extension RawRepresentable where Self: Hashable {

    // Returns the number of elements in a RawRepresentable data structure
    static var elementsCount: Int {
        var i = 1
        while (withUnsafePointer(to: &i, {
            return $0.withMemoryRebound(to: self, capacity: 1, { return 
                   $0.pointee })
        }).hashValue != 0) {
            i += 1
        }
        return i
}

0

Tôi đã tự giải quyết vấn đề này bằng cách tạo một giao thức (EnumIntArray) và một hàm tiện ích toàn cầu (enumIntArray) để dễ dàng thêm biến "Tất cả" vào bất kỳ enum nào (sử dụng swift 1.2). Biến "all" sẽ chứa một mảng gồm tất cả các phần tử trong enum để bạn có thể sử dụng all.count cho số đếm

Nó chỉ hoạt động với các enum sử dụng các giá trị thô của kiểu Int nhưng có lẽ nó có thể cung cấp một số nguồn cảm hứng cho các loại khác.

Nó cũng giải quyết các vấn đề "khoảng cách trong đánh số" và "quá nhiều thời gian để lặp lại" mà tôi đã đọc ở trên và ở nơi khác.

Ý tưởng là thêm giao thức EnumIntArray vào enum của bạn và sau đó xác định biến tĩnh "tất cả" bằng cách gọi hàm enumIntArray và cung cấp cho nó phần tử đầu tiên (và cuối cùng nếu có khoảng trống trong việc đánh số).

Bởi vì biến tĩnh chỉ được khởi tạo một lần, nên chi phí đi qua tất cả các giá trị thô chỉ đánh vào chương trình của bạn một lần.

ví dụ (không có khoảng trống):

enum Animals:Int, EnumIntArray
{ 
  case Cat=1, Dog, Rabbit, Chicken, Cow
  static var all = enumIntArray(Animals.Cat)
}

ví dụ (có khoảng trống):

enum Animals:Int, EnumIntArray
{ 
  case Cat    = 1,  Dog, 
  case Rabbit = 10, Chicken, Cow
  static var all = enumIntArray(Animals.Cat, Animals.Cow)
}

Đây là mã thực hiện nó:

protocol EnumIntArray
{
   init?(rawValue:Int)
   var rawValue:Int { get }
}

func enumIntArray<T:EnumIntArray>(firstValue:T, _ lastValue:T? = nil) -> [T]
{
   var result:[T] = []
   var rawValue   = firstValue.rawValue
   while true
   { 
     if let enumValue = T(rawValue:rawValue++) 
     { result.append(enumValue) }
     else if lastValue == nil                     
     { break }

     if lastValue != nil
     && rawValue  >  lastValue!.rawValue          
     { break }
   } 
   return result   
}

0

Hoặc bạn chỉ có thể định nghĩa _countbên ngoài enum và đính kèm tĩnh:

let _count: Int = {
    var max: Int = 0
    while let _ = EnumName(rawValue: max) { max += 1 }
    return max
}()

enum EnumName: Int {
    case val0 = 0
    case val1
    static let count = _count
}

Theo cách đó, bất kể bạn tạo ra bao nhiêu enum, nó sẽ chỉ được tạo một lần.

(xóa câu trả lời này nếu staticcó)


0

Phương pháp sau đến từ CoreKit và tương tự như câu trả lời mà một số người khác đã đề xuất. Điều này hoạt động với Swift 4.

public protocol EnumCollection: Hashable {
    static func cases() -> AnySequence<Self>
    static var allValues: [Self] { get }
}

public extension EnumCollection {

    public static func cases() -> AnySequence<Self> {
        return AnySequence { () -> AnyIterator<Self> in
            var raw = 0
            return AnyIterator {
                let current: Self = withUnsafePointer(to: &raw) { $0.withMemoryRebound(to: self, capacity: 1) { $0.pointee } }
                guard current.hashValue == raw else {
                    return nil
                }
                raw += 1
                return current
            }
        }
    }

    public static var allValues: [Self] {
        return Array(self.cases())
    }
}

enum Weekdays: String, EnumCollection {
    case sunday, monday, tuesday, wednesday, thursday, friday, saturday
}

Sau đó, bạn chỉ cần gọi Weekdays.allValues.count.


0
enum WeekDays : String , CaseIterable
{
  case monday = "Mon"
  case tuesday = "Tue"
  case wednesday = "Wed"
  case thursday = "Thu"
  case friday = "Fri"
  case saturday = "Sat"
  case sunday = "Sun"
}

var weekdays = WeekDays.AllCases()

print("\(weekdays.count)")

-1
struct HashableSequence<T: Hashable>: SequenceType {
    func generate() -> AnyGenerator<T> {
        var i = 0
        return AnyGenerator {
            let next = withUnsafePointer(&i) { UnsafePointer<T>($0).memory }
            if next.hashValue == i {
                i += 1
                return next
            }
            return nil
        }
    }
}

extension Hashable {
    static func enumCases() -> Array<Self> {
        return Array(HashableSequence())
    }

    static var enumCount: Int {
        return enumCases().enumCount
    }
}

enum E {
    case A
    case B
    case C
}

E.enumCases() // [A, B, C]
E.enumCount   //  3

nhưng hãy cẩn thận với việc sử dụng trên các loại không enum. Một số cách giải quyết có thể là:

struct HashableSequence<T: Hashable>: SequenceType {
    func generate() -> AnyGenerator<T> {
        var i = 0
        return AnyGenerator {
            guard sizeof(T) == 1 else {
                return nil
            }
            let next = withUnsafePointer(&i) { UnsafePointer<T>($0).memory }
            if next.hashValue == i {
                i += 1
                return next
            }

            return nil
        }
    }
}

extension Hashable {
    static func enumCases() -> Array<Self> {
        return Array(HashableSequence())
    }

    static var enumCount: Int {
        return enumCases().count
    }
}

enum E {
    case A
    case B
    case C
}

Bool.enumCases()   // [false, true]
Bool.enumCount     // 2
String.enumCases() // []
String.enumCount   // 0
Int.enumCases()    // []
Int.enumCount      // 0
E.enumCases()      // [A, B, C]
E.enumCount        // 4

-1

Nó có thể sử dụng hằng số tĩnh chứa giá trị cuối cùng của phép liệt kê cộng với một.

enum Color : Int {
    case  Red, Orange, Yellow, Green, Cyan, Blue, Purple

    static let count: Int = Color.Purple.rawValue + 1

    func toUIColor() -> UIColor{
        switch self {
            case .Red:
                return UIColor.redColor()
            case .Orange:
                return UIColor.orangeColor()
            case .Yellow:
                return UIColor.yellowColor()
            case .Green:
                return UIColor.greenColor()
            case .Cyan:
                return UIColor.cyanColor()
            case .Blue:
                return UIColor.blueColor()
            case .Purple:
                return UIColor.redColor()
        }
    }
}

-3

Điều này là nhỏ, nhưng tôi nghĩ rằng một giải pháp O (1) tốt hơn sẽ là như sau ( CHỈ nếu enum của bạn Intbắt đầu ở x, v.v.):

enum Test : Int {
    case ONE = 1
    case TWO
    case THREE
    case FOUR // if you later need to add additional enums add above COUNT so COUNT is always the last enum value 
    case COUNT

    static var count: Int { return Test.COUNT.rawValue } // note if your enum starts at 0, some other number, etc. you'll need to add on to the raw value the differential 
}

Câu trả lời được chọn hiện tại tôi vẫn tin là câu trả lời tốt nhất cho tất cả các enum, trừ khi bạn đang làm việc với Intthì tôi khuyên bạn nên giải pháp này.


3
Thêm một giá trị cho enum của bạn mà không thực sự đại diện cho loại enum là mùi mã xấu. Tôi thấy thật khó để thậm chí biện minh bao gồm cả "TẤT CẢ" hoặc "KHÔNG" mặc dù đôi khi nó có thể bị cám dỗ. Bao gồm một "COUNT" chỉ để hack xung quanh vấn đề này là rất hôi thối.
Michael Peterson

1
Hôi thối? Nếu bạn muốn gọi nó là chắc chắn. Biểu diễn? Đúng. Tùy thuộc vào nhà phát triển để quyết định ưu và nhược điểm. Đây thực sự là cùng một câu trả lời cho câu trả lời của Zorayr ở trên, nơi anh đi sâu vào chi tiết hơn về nó và câu trả lời mới được chấp nhận cũng tương tự. Nhưng cho đến khi swift thêm một api cho nó; đây là những gì một số người trong chúng ta đã quyết định sử dụng. Bạn có thể thêm một hàm xác nhận giá trị enum guardchống lại COUNTvà đưa ra lỗi, trả về false, v.v. để giải quyết mối quan tâm của bạn về biểu diễn các loại.
Drmorgan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.