Reputation: 591
So I'm very new to Swift at the moment and am working on a class (as below).
The variable selectedOption
can be an array of String
or Int
and the methods need to compare the values received against that array.
The below code works, but I don't like the fact that I'm type checking and replicating the code to compare Strings then again to compare Ints in methods isSelected
and removeSelectedItem
Such as
if selectedOption is String {
return (self.selectedOption!.indexOf({ $0 as! String == selectedOption as! String }) != nil)
} else if ( selectedOption is Int ) {
return (self.selectedOption!.indexOf({ $0 as! Int == selectedOption as! Int })) != nil
}
There must be a better way?
public class SearchOption {
private var title: String
private var allowAny: Bool
private var allowMultiple: Bool
private var dependencies: [SearchOption]?
// Store the selected Item in an array of AnyObjects.
private var selectedOption: [AnyObject]?
init(title: String, allowAny: Bool, allowMultiple: Bool, dependencies: [SearchOption]?) {
self.title = title
self.allowAny = allowAny
self.allowMultiple = allowMultiple
self.dependencies = dependencies
}
public func setSelectedItem(selectedOption: AnyObject) -> Void {
if self.selectedOption == nil || !self.allowMultiple{
self.selectedOption = [AnyObject]()
}
self.selectedOption?.append(selectedOption)
}
public func getSelectedItem() -> [AnyObject]? {
return self.selectedOption
}
public func removeSelectedItem(selectedOption: AnyObject) -> Void {
if self.selectedOption != nil {
if selectedOption is String {
self.selectedOption = self.selectedOption!.filter() { $0 as! String != selectedOption as! String }
} else if ( selectedOption is Int ) {
self.selectedOption = self.selectedOption!.filter() { $0 as! Int != selectedOption as! Int }
}
}
}
public func isSelected(selectedOption: AnyObject) -> Bool {
if self.selectedOption != nil {
if selectedOption is String {
return (self.selectedOption!.indexOf({ $0 as! String == selectedOption as! String }) != nil)
} else if ( selectedOption is Int ) {
return (self.selectedOption!.indexOf({ $0 as! Int == selectedOption as! Int })) != nil
}
}
return false
}
public func clearSelectedItems() -> Void {
self.selectedOption = nil
}
public func checkDependencies() -> Bool {
if dependencies != nil {
for dependency in dependencies! {
if dependency.getSelectedItem() == nil {
return false
}
}
}
return true
}
}
var make: SearchOption = SearchOption(title: "Make", allowAny: true, allowMultiple: true, dependencies: nil)
make.setSelectedItem("Vauxhall")
make.setSelectedItem("Mazda")
make.setSelectedItem("Audi")
print(make.getSelectedItem())
make.removeSelectedItem("Mazda")
print(make.getSelectedItem())
print(make.isSelected("Audi"))
Outputs:
Optional([Vauxhall, Mazda, Audi])
Optional([Vauxhall, Audi])
true
Upvotes: 0
Views: 130
Reputation: 539835
Expanding on the comments already made to the question: You should make
the class generic, so that it can be used with String
or Int
items. What you need is that the items can be compared with ==
,
i.e. that the type is Equatable
.
The class declaration would then be
public class SearchOption<T : Equatable> {
// ...
}
and all occurrences of AnyObject
have to be replaced by T
.
The isSelected
method simplifies to
public func isSelected(selectedOption: T) -> Bool {
if self.selectedOption != nil {
return self.selectedOption!.contains( { $0 == selectedOption })
}
return false
}
which can be further simplified using optional chaining
and the nil-coalescing operator ??
:
public func isSelected(selectedOption: T) -> Bool {
return self.selectedOption?.contains( { $0 == selectedOption }) ?? false
}
Similarly:
public func removeSelectedItem(selectedOption: T) -> Void {
self.selectedOption = self.selectedOption?.filter( { $0 != selectedOption } )
}
For String
items you would then create an instance of the class
with
let make = SearchOption<String>(title: "Make", allowAny: true, allowMultiple: true, dependencies: nil)
Upvotes: 2
Reputation: 591
Managed to solve the problem using Generics and Equatable (I've never really used these before so forgive me)
In the class T is constrained to a type of Equatable, which seems to keep .filter()
and .indexOf
happy.
When creating the instance you pass the type you'll be using:
var make: SearchOption = SearchOption<String>(title: "Make", allowAny: true, allowMultiple: true, dependencies: nil)
The resulting class looks as follows
public class SearchOption<T: Equatable> {
private var title: String
private var allowAny: Bool
private var allowMultiple: Bool
private var dependencies: [SearchOption]?
// Store the selected Item in an array of AnyObjects.
private var selectedOption: [T]?
init(title: String, allowAny: Bool, allowMultiple: Bool, dependencies: [SearchOption]?) {
self.title = title
self.allowAny = allowAny
self.allowMultiple = allowMultiple
self.dependencies = dependencies
}
public func setSelectedItem(selectedOption: T) -> Void {
if self.selectedOption == nil || !self.allowMultiple {
self.selectedOption = [T]()
}
self.selectedOption?.append(selectedOption)
}
public func getSelectedItem() -> [T]? {
return self.selectedOption
}
public func removeSelectedItem(selectedOption: T) -> Void {
if self.selectedOption != nil {
self.selectedOption = self.selectedOption!.filter() { $0 != selectedOption }
}
}
public func isSelected(selectedOption: T) -> Bool {
if self.selectedOption != nil {
return (self.selectedOption!.indexOf({ $0 == selectedOption }) != nil)
}
return false
}
public func clearSelectedItems() -> Void {
self.selectedOption = nil
}
public func checkDependencies() -> Bool {
if dependencies != nil {
for dependency in dependencies! {
if dependency.getSelectedItem() == nil {
return false
}
}
}
return true
}
}
var make: SearchOption = SearchOption<String>(title: "Make", allowAny: true, allowMultiple: true, dependencies: nil)
make.setSelectedItem("Vauxhall")
make.setSelectedItem("Mazda")
make.setSelectedItem("Audi")
print(make.getSelectedItem())
make.removeSelectedItem("Audi")
print(make.getSelectedItem())
print(make.isSelected("Mazda"))
Upvotes: 1