Swift has the OptionSet type, which basically adds set operations to C-Style bit flags. Apple is using them pretty extensively in their frameworks. Examples include the options parameter in animate(withDuration:delay:options:animations:completion:).
On the plus side, it lets you use clean code like:
options: [.allowAnimatedContent, .curveEaseIn]
However, there is a downside as well.
If I want to display the specified values of an OptionSet, there doesn't seem to be a clean way to do it:
let options: UIViewAnimationOptions = [.allowAnimatedContent, .curveEaseIn]
print("options = " + String(describing: options))
Displays the very unhelpful message:
options = UIViewAnimationOptions(rawValue: 65664)
The docs for some of these bit fields expresses the constant as a power-of-two value:
flag0 = Flags(rawValue: 1 << 0)
But the docs for my example OptionSet, UIViewAnimationOptions, doesn't tell you anything about the numeric value of these flags and figuring out bits from decimal numbers is not straightforward.
Question:
Is there some clean way to map an OptionSet to the selected values?
My desired output would be something like:
options = UIViewAnimationOptions([.allowAnimatedContent, .curveEaseIn])
But I can't think of a way to do this without adding messy code that would require me to maintain a table of display names for each flag.
(I'm interested in doing this for both system frameworks and custom OptionSets I create in my own code.)
Enums let you have both a name and a raw value for the enum, but those don't support the set functions you get with OptionSets.
Here is one approach I've taken, using a dictionary and iterating over the keys. Not great, but it works.
struct MyOptionSet: OptionSet, Hashable, CustomStringConvertible {
let rawValue: Int
static let zero = MyOptionSet(rawValue: 1 << 0)
static let one = MyOptionSet(rawValue: 1 << 1)
static let two = MyOptionSet(rawValue: 1 << 2)
static let three = MyOptionSet(rawValue: 1 << 3)
var hashValue: Int {
return self.rawValue
}
static var debugDescriptions: [MyOptionSet:String] = {
var descriptions = [MyOptionSet:String]()
descriptions[.zero] = "zero"
descriptions[.one] = "one"
descriptions[.two] = "two"
descriptions[.three] = "three"
return descriptions
}()
public var description: String {
var result = [String]()
for key in MyOptionSet.debugDescriptions.keys {
guard self.contains(key),
let description = MyOptionSet.debugDescriptions[key]
else { continue }
result.append(description)
}
return "MyOptionSet(rawValue: \(self.rawValue)) \(result)"
}
}
let myOptionSet = MyOptionSet([.zero, .one, .two])
// prints MyOptionSet(rawValue: 7) ["two", "one", "zero"]
This article in NSHipster gives an alternative to OptionSet that offers all the features of an OptionSet, plus easy logging:
https://nshipster.com/optionset/
If you simply add a requirement that the Option type be CustomStringConvertible, you can log Sets of this type very cleanly. Below is the code from the NSHipster site - the only change being the addition of CustomStringConvertible conformance to the Option class
protocol Option: RawRepresentable, Hashable, CaseIterable, CustomStringConvertible {}
enum Topping: String, Option {
case pepperoni, onions, bacon,
extraCheese, greenPeppers, pineapple
//I added this computed property to make the class conform to CustomStringConvertible
var description: String {
return ".\(self.rawValue)"
}
}
extension Set where Element == Topping {
static var meatLovers: Set<Topping> {
return [.pepperoni, .bacon]
}
static var hawaiian: Set<Topping> {
return [.pineapple, .bacon]
}
static var all: Set<Topping> {
return Set(Element.allCases)
}
}
typealias Toppings = Set<Topping>
extension Set where Element: Option {
var rawValue: Int {
var rawValue = 0
for (index, element) in Element.allCases.enumerated() {
if self.contains(element) {
rawValue |= (1 << index)
}
}
return rawValue
}
}
Then using it:
let toppings: Set<Topping> = [.onions, .bacon]
print("toppings = \(toppings), rawValue = \(toppings.rawValue)")
That outputs
toppings = [.onions, .bacon], rawValue = 6
Just like you want it to.
That works because a Set displays its members as a comma-delimited list inside square brackets, and uses the description property of each set member to display that member. The description property simply displays each item (the enum's name as a String) with a . prefix
And since the rawValue of a Set<Option> is the same as an OptionSet with the same list of values, you can convert between them readily.
I wish Swift would just make this a native language feature for OptionSets.
StrOptionSet Protocol:
Add a labels set property to test each label value on Self.
StrOptionSet Extension:
Filter out which is not intersected.
Return the label text as array.
Joined with "," as CustomStringConvertible::description
Here is the snippet:
protocol StrOptionSet : OptionSet, CustomStringConvertible {
typealias Label = (Self, String)
static var labels: [Label] { get }
}
extension StrOptionSet {
var strs: [String] { return Self.labels
.filter{ (label: Label) in self.intersection(label.0).isEmpty == false }
.map{ (label: Label) in label.1 }
}
public var description: String { return strs.joined(separator: ",") }
}
Add the label set for target option set VTDecodeInfoFlags.
extension VTDecodeInfoFlags : StrOptionSet {
static var labels: [Label] { return [
(.asynchronous, "asynchronous"),
(.frameDropped, "frameDropped"),
(.imageBufferModifiable, "imageBufferModifiable")
]}
}
Use it
let flags: VTDecodeInfoFlags = [.asynchronous, .frameDropped]
print("flags:", flags) // output: flags: .asynchronous,frameDropped
This is how I did it.
public struct Toppings: OptionSet {
public let rawValue: Int
public static let cheese = Toppings(rawValue: 1 << 0)
public static let onion = Toppings(rawValue: 1 << 1)
public static let lettuce = Toppings(rawValue: 1 << 2)
public static let pickles = Toppings(rawValue: 1 << 3)
public static let tomatoes = Toppings(rawValue: 1 << 4)
public init(rawValue: Int) {
self.rawValue = rawValue
}
}
extension Toppings: CustomStringConvertible {
static public var debugDescriptions: [(Self, String)] = [
(.cheese, "cheese"),
(.onion, "onion"),
(.lettuce, "lettuce"),
(.pickles, "pickles"),
(.tomatoes, "tomatoes")
]
public var description: String {
let result: [String] = Self.debugDescriptions.filter { contains($0.0) }.map { $0.1 }
let printable = result.joined(separator: ", ")
return "\(printable)"
}
}
struct MyOptionSet: OptionSet {
let rawValue: UInt
static let healthcare = MyOptionSet(rawValue: 1 << 0)
static let worldPeace = MyOptionSet(rawValue: 1 << 1)
static let fixClimate = MyOptionSet(rawValue: 1 << 2)
static let exploreSpace = MyOptionSet(rawValue: 1 << 3)
}
extension MyOptionSet: CustomStringConvertible {
static var debugDescriptions: [(Self, String)] = [
(.healthcare, "healthcare"),
(.worldPeace, "world peace"),
(.fixClimate, "fix the climate"),
(.exploreSpace, "explore space")
]
var description: String {
let result: [String] = Self.debugDescriptions.filter { contains($0.0) }.map { $0.1 }
return "MyOptionSet(rawValue: \(self.rawValue)) \(result)"
}
}
Usage
var myOptionSet: MyOptionSet = []
myOptionSet.insert(.healthcare)
print("here is my options: \(myOptionSet)")
Related
This is the case:
public enum NodeFeature: UInt16 {
case relay = 0x01
case proxy = 0x02
case friend = 0x04
case lpn = 0x08
}
public struct NodeFeatures {
public let rawValue: UInt16
public init(rawValue: UInt16) {
self.rawValue = rawValue
}
public init(features: NodeFeature...) {
var rawValue = UInt16(0)
for feature in features {
rawValue |= feature.rawValue
}
self.rawValue = rawValue
}
public func hasFeature(_ feature: NodeFeature) -> Bool {
return rawValue & feature.rawValue > 0
}
}
And this is a response from server:
"feature": {
"relay": true,
"proxy": false,
"friend": false,
"lowPower": false
}
Now I need to create an instance of NodeFeatures with only true values:
var features = [NodeFeature]() // how to declare and prepare the list of args?
if true {
features.append(.first)
} else if true {
features.append(.third)
}
let wrapper = NodeFeatures(features: features) //... to pass it as a variable to the initializer.
But the error is following:
Cannot convert value of type '[NodeFeature]' to expected argument type 'NodeFeatures'
You cannot pass an array to a function taking a variadic argument,
or dynamically "build" a variadic argument list, compare e.g.
Passing an array to a function with variable number of args in Swift.
But fortunately, the type has another initializer
public init(rawValue: UInt16)
which you can use in different ways.
Option 1: Use an integer bit mask to assemble the features
instead of an array:
var rawFeatures = UInt16(0)
if condition {
rawFeatures |= NodeFeature.relay.rawValue
} else if condition {
rawFeatures |= NodeFeature.proxy.rawValue
}
let wrapper = NodeFeatures(rawValue: rawFeatures)
Option 2: Keep your array, but compute the combined raw value
to create the NodeFeatures value:
var features = [NodeFeature]()
if condition {
features.append(.relay)
} else if condition {
features.append(.proxy)
}
let rawFeatures = features.reduce(0, { $0 | $1.rawValue })
let wrapper = NodeFeatures(rawValue: rawFeatures)
Option 3: Define another initializer taking an array argument
in an extension:
extension NodeFeatures {
public init(features: [NodeFeature]) {
let rawValue = features.reduce(0, { $0 | $1.rawValue })
self.init(rawValue: rawValue)
}
}
Now you can pass your array directly:
var features = [NodeFeature]()
if condition {
features.append(.relay)
} else if condition {
features.append(.proxy)
}
let wrapper = NodeFeatures(features: features)
I am trying to create an enum of a struct that I would like to initialize:
struct CustomStruct {
var variable1: String
var variable2: AnyClass
var variable3: Int
init (variable1: String, variable2: AnyClass, variable3: Int) {
self.variable1 = variable1
self.variable2 = variable2
self.variable3 = variable3
}
}
enum AllStructs: CustomStruct {
case getData
case addNewData
func getAPI() -> CustomStruct {
switch self {
case getData:
return CustomStruct(variable1:"data1", variable2: SomeObject.class, variable3: POST)
case addNewData:
// Same to same
default:
return nil
}
}
}
I get the following errors:
Type AllStructs does not conform to protocol 'RawRepresentable'
I am assuming that enums cannot be used this way. We must use primitives.
It should be:
struct CustomStruct {
var apiUrl: String
var responseType: AnyObject
var httpType: Int
init (variable1: String, variable2: AnyObject, variable3: Int) {
self.apiUrl = variable1
self.responseType = variable2
self.httpType = variable3
}
}
enum MyEnum {
case getData
case addNewData
func getAPI() -> CustomStruct {
switch self {
case .getData:
return CustomStruct(variable1: "URL_TO_GET_DATA", variable2: 11 as AnyObject, variable3: 101)
case .addNewData:
return CustomStruct(variable1: "URL_TO_ADD_NEW_DATA", variable2: 12 as AnyObject, variable3: 102)
}
}
}
Usage:
let data = MyEnum.getData
let myObject = data.getAPI()
// this should logs: "URL_TO_GET_DATA 11 101"
print(myObject.apiUrl, myObject.responseType, myObject.httpType)
Note that upon Naming Conventions, struct should named as CustomStruct and enum named as MyEnum.
In fact, I'm not pretty sure of the need of letting CustomStruct to be the parent of MyEnum to achieve what are you trying to; As mentioned above in the snippets, you can return an instance of the struct based on what is the value of the referred enum.
I'm not commenting on the choice to use an enum here, but just explaining why you got that error and how to declare an enum that has a custom object as parent.
The error shows you the problem, CustomStruct must implement RawRepresentable to be used as base class of that enum.
Here is a simplified example that shows you what you need to do:
struct CustomStruct : ExpressibleByIntegerLiteral, Equatable {
var rawValue: Int = 0
init(integerLiteral value: Int){
self.rawValue = value
}
static func == (lhs: CustomStruct, rhs: CustomStruct) -> Bool {
return
lhs.rawValue == rhs.rawValue
}
}
enum AllStructs: CustomStruct {
case ONE = 1
case TWO = 2
}
A few important things that we can see in this snippet:
The cases like ONE and TWO must be representable with a Swift literal, check this Swift 2 post for a list of available literals (int,string,array,dictionary,etc...). But please note that in Swift 3, the LiteralConvertible protocols are now called ExpressibleByXLiteral after the Big Swift Rename.
The requirement to implement RawRepresentable is covered implementing one of the Expressible protocols (init?(rawValue:) will leverage the initializer we wrote to support literals).
Enums must also be Equatable , so you'll have to implement the equality operator for your CustomStruct base type.
Did you try conforming to RawRepresentable like the error is asking?
Using JSON representation should work for variable1 and variable3. Some extra work may be required for variable2.
struct CustomStruct: RawRepresentable {
var variable1: String
var variable2: AnyClass
var variable3: Int
init?(rawValue: String) {
guard let data = rawValue.data(using: .utf8) else {
return nil
}
guard let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else {
return nil
}
self.variable1 = (json["variable1"] as? String) ?? ""
self.variable2 = (json["variable2"] as? AnyClass) ?? AnyClass()
self.variable3 = (json["variable3"] as? Int) ?? 0
}
var rawValue: String {
let json = ["variable1": self.variable1,
"variable2": self.variable2,
"variable3": self.variable3
]
guard let data = try? JSONSerialization.data(withJSONObject: json, options: []) else {
return ""
}
return String(data: data, encoding: .utf8) ?? ""
}
}
According to the documentation:
If a value (known as a “raw” value) is provided for each enumeration case, the value can be a string, a character, or a value of any integer or floating-point type.
So yes, you cannot set a struct type to be enum's raw value.
In your case I would suggest using string as the enum raw value and some dictionary mapping these strings to CUSTOM_STRUCT type.
A bit late on the party but maybe useful for someone else. I would consider to simply use computed variables instead of a struct.
enum MyEnum {
case getData
case addNewData
var variable1: String {
switch self {
case .getData: return "data1"
case .addNewData: return "data2"
}
}
var variable2: Int {
switch self {
case .getData: return 1
case .addNewData: return 2
}
}
// ....
}
Usage:
let data = MyEnum.getData
print (data.variable1) // "data1"
I'd like to use an array of custom enums as a dictionary key, but I'm having difficulty figuring out how to make the array conform to Hashable. The compiler tells me that [Symbol] doesn't conform to Hashable. What do I have to do to get this to compile?
I messed around with an extension to Array where Element:Symbol, but I couldn't figure out how to add a protocol that way.
enum Symbol:Hashable, Equatable {
case Dot
case Dash
var value:Int {
get {
switch self {
case .Dot: return 0
case .Dash: return 1
}
}
var hashValue:Int {
return self.value
}
}
func ==(left: Symbol, right: Symbol) -> Bool {
return left.value == right.value
}
struct MorseDictionary {
static let symbolToStringDictionary:[[Symbol]:String] = [
[.Dot, .Dash]:"A"
]
}
In Swift 2.2 you cannot create an extension restricted to an Array of a specific type
So you cannot conform an Array of Symbol to Hashable or Equatable.
This means you cannot use an Array of Symbol as key in a Dictionary.
Of course you can create an extension making Array (every array!!) Equatable and Hashable but it's a crazy approach since obviously you will never be able to provide a valid implementation.
However you can follow another approach
First of all your enum can be rewritten this way
enum Symbol: Int {
case Dot = 0, Dash
}
Next you'll need a wrapper for an array of Symbol
struct Symbols: Hashable, Equatable {
let value: [Symbol]
// you can use a better logic here
var hashValue: Int { return value.first?.hashValue ?? 0 }
}
func ==(left: Symbols, right:Symbols) -> Bool {
return !zip(left.value, right.value).contains { $0.0 != $0.1 }
}
Now you can create your dictionary
let dict: [Symbols:String] = [Symbols(value: [.Dot, .Dash]) : "A"]
I have same idea with #appzYourLife. So do not accept my answer. The worth thing here, I have implemented the hash function for Symbols.
func ==(left: Symbols, right: Symbols) -> Bool {
return left.value == right.value
}
enum Symbol: Int {
case Dot = 0
case Dash = 1
case Count = 2
}
struct Symbols: Hashable {
let symbols: [Symbol]
init(symbols: [Symbol]) {
self.symbols = symbols
}
var value: Int {
var sum = 0
var i = 1
symbols.forEach({ (s) in
sum += s.rawValue * i
i = i * Symbol.Count.rawValue
})
return sum
}
var hashValue: Int {
return value % Int(pow(Double(2), Double(Symbol.Count.rawValue)))
}
}
struct MorseDictionary {
static let symbolToStringDictionary: [Symbols: String] = [
Symbols(symbols: [.Dot, .Dash]): "A",
Symbols(symbols: [.Dash, .Dot]): "B",
Symbols(symbols: [.Dash, .Dash]): "C",
Symbols(symbols: [.Dot, .Dot]): "D",
]
}
Clients's code:
MorseDictionary.symbolToStringDictionary[Symbols(symbols: [.Dot, .Dash])]
MorseDictionary.symbolToStringDictionary[Symbols(symbols: [.Dash, .Dot])]
MorseDictionary.symbolToStringDictionary[Symbols(symbols: [.Dash, .Dash])]
MorseDictionary.symbolToStringDictionary[Symbols(symbols: [.Dot, .Dot])]
Results in:
"A"
"B"
"C"
"D"
I am trying to filter an array containing classes so that only the class that is found in another array will be added to an array. This is what I have so far:
class Match : Equatable {
var name: String
var value: String
init(name: String, value: String) {
self.name = name
self.value = value
}
func ==(lhs: Match, rhs: Match) -> Bool {
return lhs.name == rhs.name && lhs.value == rhs.value
}
// attempt to filter array containing Match structs
let terms = [Match]()
let someOtherObjects = [Match]()
let sampleMatch = Match(name: "someName", value: "someValue")
someOtherObjects.append(sampleMatch)
filteredTerms = terms.filter { term in
if attemptedCombos.contains(sampleMatch) {
return true
}
}
However the compiler does not let me build with the error:
"Cannot convert value of type 'Match' to expected argument type
'#noescape (Match) throws -> Bool'
Any ideas?
Updated using Set (as it seems as if you want the intersection of two [Match] arrays). In addition to Equatable, you must let your Match class conform to Hashable for instances of it to be allowed as elements in a Set.
class Match : Equatable, Hashable {
var name: String
var value: String
init(_ name: String, _ value: String) {
self.name = name
self.value = value
}
var hashValue: Int {
get {
return name.hashValue << 20 + value.hashValue
}
}
}
func ==(lhs: Match, rhs: Match) -> Bool {
return lhs.name == rhs.name && lhs.value == rhs.value
}
Example:
/* Example */
var mySetA : Set<Match> = [Match("foo", "bar"), Match("foo", "foo"), Match("barbar", "foo")]
var mySetB = Set<Match>()
mySetB.insert(Match("barbar", "bar"))
mySetB.insert(Match("bar", "foo"))
mySetB.insert(Match("foo", "bar"))
mySetB.insert(Match("foo", "foo"))
let myIntersect = mySetA.intersect(mySetB)
for match in myIntersect {
print("name: " + match.name + ", value: " + match.value)
}
/* name: foo, value: foo
name: foo, value: bar */
After chatting with the OP we've solved the issue in chat. I'm not sure what the convention are here, but I'll summarize the additional information given by the OP in chat, and the solution to the problem. Consider the block above as a solution to the question above, and the block below as a quite narrow solution to the question above complemented with more specifics from the OP.
The "filter" array of objects are of a different class type (Tern) than the array to be filtered (Match), where these two classes share some class properties.
A natural enquiry to the OP was if it was acceptable to let both these classes have one common superclass; it was.
In addition to the above, one of the properties common for both classes were of a custom enum type, posted in chat by the author.
The final solution used, as above, Set and .intersect():
/* custom enum given by OP in chat */
enum Declension : String {
case firstDeclensionFem = "a:a:am:ae:ae:a:ae:ae:as:arum:is:is"
case secondDeclensionMasc = "us:er:um:i:o:o:i:i:os:orum:is:is"
case secondDeclensionNeu = "um:um:um:i:o:o:a:a:a:orum:is:is"
case thirdDeclensionMasc = " : :em:is:i:e:es:es:es:um:ibus:ibus"
case thirdDeclensionMascSpecial = " : :em:is:i:e:es:es:es:ium:ibus:ibus"
case fourthFem = "us:us:um:us:ui:u:us:us:us:uum:ibus:ibus"
case fourthNeu = "u:u:u:us:u:u:ua:ua:ua:uum:ibus:ibus"
case fifthMasc = "es:es:em:ei:ei:e:es:es:es:erum:ebus:ebus"
case unknown
static let allValues = [firstDeclensionFem, secondDeclensionMasc, secondDeclensionNeu, thirdDeclensionMasc, thirdDeclensionMascSpecial, fourthFem, fourthNeu, fifthMasc]
}
/* use a superclass and let the sets below have members that
are declared to be of this superclass type */
class MyMatchTypes : Equatable, Hashable {
var latin: String
var declension: Declension
init(_ latin: String, _ declension: Declension) {
self.latin = latin
self.declension = declension
}
var hashValue: Int {
get {
return latin.hashValue << 20 + declension.hashValue
}
}
}
func ==(lhs: MyMatchTypes, rhs: MyMatchTypes) -> Bool {
return lhs.latin == rhs.latin && lhs.declension == rhs.declension
}
/* the two classes mentioned in chat: use as subclasses */
class Term : MyMatchTypes {
var meaning: String
var notes: String
var genStem: String
init(_ latin: String, _ declension: Declension, _ meaning: String, _ genStem: String, _ notes: String) {
self.meaning = meaning
self.notes = notes
self.genStem = genStem
super.init(latin, declension)
}
}
class Match : MyMatchTypes {
// ... add stuff
// super init is OK
}
/* Example */
/* ----------------------------------------------- */
/* Set of `Match` objects */
var mySetA = Set<MyMatchTypes>()
mySetA.insert(Match("foo", Declension.firstDeclensionFem))
mySetA.insert(Match("bar", Declension.fourthFem))
mySetA.insert(Match("foofoo", Declension.fourthFem))
mySetA.insert(Match("barbar", Declension.fifthMasc))
/* Set of `Term` objects */
var mySetB = Set<MyMatchTypes>()
mySetB.insert(Term("fooshy", Declension.fourthFem, "a", "b", "c"))
mySetB.insert(Term("barbar", Declension.fifthMasc, "a", "b", "c"))
mySetB.insert(Term("bar", Declension.fourthFem, "a", "b", "c"))
mySetB.insert(Term("foofoo", Declension.firstDeclensionFem, "a", "b", "c"))
mySetB.insert(Term("foobar", Declension.fourthFem, "a", "b", "c"))
/* compute intersection */
let myIntersect = mySetA.intersect(mySetB)
for obj in myIntersect {
print("latin: " + obj.latin + ", declension: \(obj.declension)")
}
/* latin: barbar, declension: fifthMasc
latin: bar, declension: fourthFem */
If Match confirms to Equatable protocol your code should work. Following code compiles successfully:
class Match : Equatable {
var name: String
var value: String
init(name: String, value: String) {
self.name = name
self.value = value
}
}
func ==(lhs: Match, rhs: Match) -> Bool {
return lhs.name == rhs.name && lhs.value == rhs.value
}
let sampleMatch1 = Match(name: "someNameA", value: "someValue")
let sampleMatch2 = Match(name: "someNameA", value: "someValue")
let sampleMatch3 = Match(name: "someNameB", value: "someValue")
let sampleMatch4 = Match(name: "someNameC", value: "someValue")
let terms = [sampleMatch1, sampleMatch3]
var someOtherObjects = [sampleMatch2, sampleMatch4]
let filteredTerms = terms.filter { term in
return someOtherObjects.contains(term)
}
Result is:
I would like to create a typed map (Dictionary) class to meet the following requirements:
func testMap() {
var map = ActivitiesMap()
var activity = Activity()
activity.title = "Activity 1"
activity.uuid = "asdf1234"
map[activity.uuid] = activity
for (key, mapActivity) in map {
logger.debug("ACTIVITY MAP: \(key)=\(mapActivity)")
}
}
In short, I want this class to both be a dictionary such that it can be used in the for loop, however I want to ensure the keys are strings and the values are Activity objects.
I tried many variations of inheriting from Dictionary or typing the class, but so far it's resulted in multiple errors.
EDIT:
I don't think a simple generic dictionary will work, such as String:Activity. I want to have extra methods in the ActivityMap class, such as getAllActivitiesBetweenDates().
I need an actual class definition, not a generic dictionary expression.
You can make it looks like dictionary by implement subscript operator
And conform to Sequence protocol to support for-in loop
struct ActivitiesMap : Sequence {
var map = [String:Activity]()
subscript(key: String) -> Activity? {
get {
return map[key]
}
set(newValue) {
map[key] = newValue
}
}
func generate() -> GeneratorOf<(String, Activity)> {
var gen = map.generate()
return GeneratorOf() {
return gen.next()
}
}
// I can't find out type of map.generator() now, if you know it, you can do
//func generate() -> /*type of map.generator()*/ {
// return map.generate();
//}
}
This works for me. Not sure what is in your ActivitiesMap class, but just typed a Dictionary
class Activity{
var title:String = "";
var uuid: String = "";
}
func testMap() {
//var map = ActivitiesMap()
var map: Dictionary< String, Activity> = Dictionary< String, Activity>();
var activity = Activity()
activity.title = "Activity 1"
activity.uuid = "asdf1234"
map[activity.uuid] = activity
for (key, mapActivity) in map {
println("ACTIVITY MAP: \(key)=\(mapActivity)")
}
}
testMap();
This is my output:
ACTIVITY MAP: asdf1234=C11lldb_expr_08Activity (has 2 children)
class Activity {
var title=""
var id=""
init(id:String, title:String) { self.id=id; self.title = title }
}
var activities = [String:Activity]()
let a1 = Activity(id:"a1", title:"title1")
let a2 = Activity(id:"a2", title:"title2")
let a3 = Activity(id:"a3", title:"title3")
activities[a1.id] = a1
activities[a2.id] = a2
activities[a3.id] = a3
for (id,activity) in activities {
println("id: \(id) - \(activity.title)")
}
should print
id: a2 - title2
id: a3 - title3
id: a1 - title1
(key order not guaranteed to be the same)
You can use typealias keyword to define nice name of any type.
Here is how it can be used for your code:
class Activity { /* your code */ }
typealias ActivityMap = Dictionary<String, Activity>
var activityDict = ActivityMap()
And to support custom functions you can write an extension, example bellow:
extension Dictionary {
func getAllActivitiesBetweenDates(fromDate:NSDate, toDate:NSDate) -> Array<Activity>
// your code
return []
}
}
Usage:
let matchedActivities = activityDict.getAllActivitiesBetweenDates(/*date*/, /*date*/)