protocol Base {
associatedtype M
var data:M { get set }
func update(data:M)
}
class ViewA : Base {
var data: String = ""
func update(data: String) {}
}
class ViewB : Base {
var data: Int = 2
func update(data: Int) {}
}
var dataArr : [Any] = ["1",2]
var viewArr : [Any] = [ViewA(), ViewB()]
func updatData() {
func update<C, T>(view:C, data:T) where C : Base, C.M == T {
view.update(data: data)
}
for i in 0..<2 {
let view = viewArr[i]
let data = dataArr[I]
// ! there is a errr here, Protocol 'Any' as a type cannot conform to 'Base'
update(view: view, data: data)
}
}
My Views conform to this 'Base' protocol which define what type of data my view use
And I want to implement this updatData function dynamic tell if data can be send to view (base on viwe.m type is same to data's type)
But it is seems to be impossible in Swift?
Array of Any object pass as Base Protocol create conflict.
so add one more class for Base class of ViewA and ViewB
protocol Base {
associatedtype M
var data: M { get set }
func update(data: M)
}
class Base1: Base {
typealias M = Any
var data: Any = ""
func update(data: Any) {
print("Udate \(data)")
}
}
class ViewA: Base1 {
//typealias M = String
//var data: String = ""
override func update(data: Any) {
print("test")
}
}
class ViewB: Base1 {
//typealias M = Int
//var data: Int = 2
override func update(data: Any) {
print(data)
print("Udate")
}
}
var dataArr: [Any] = ["1", 2]
var viewArr: [Any] = [ViewA(), ViewB()]
func updatData() {
func update<C, T>(view: C, data: T) where C: Base, C.M == T {
view.update(data: data)
}
for i in 0..<2 {
let view = viewArr[i]
let data = dataArr[i]
update(view: view as! Base1, data: data)
}
}
You want to create a type erased Base concrete type here: AnyBase:
public final class AnyBase: Base {
fileprivate let _boxed: _Box<M>
public init<Concrete: Base>(_ concrete: Concrete) where Concrete.M == M {
self._boxed = _ConcreteBox(concrete)
}
// Base conformance
public var data: M { _boxed.data }
public func update(data: M) {
_boxed.update(data: data)
}
// Type erasure
fileprivate class _Box<T>: Base {
init() {
guard type(of: self) != _Box.self else { fatalError("Can't create _Box instances, create a sub class instance instead ") }
}
// Base conformance
var base: M {
get { fatalError("Must override") }
set { fatalError("Must override") }
}
func update(data: M) {
fatalError("Must override")
}
}
fileprivate final class _ConcreteBox<Concrete: Base>: _Box<Concrete.M> where M == Concrete.M {
let _concrete: Concrete
init(_ concrete: Concrete) {
self._concrete = concrete
super.init()
}
// Base conformance
override var data: {
get { _concrete.data }
set { _concrete.data = newValue }
}
override func update(data: M) {
_concrete.update(data: data)
}
}
}
Now you can store different concrete instances of Base<M> in an array by adopting the type erased AnyBase<M> instead of using Any in your arrays.
protocol Decodable {
init?(data: [String: AnyObject])
}
struct A: Decodable {
var data: [String: AnyObject]!
init?(data: [String: AnyObject]) {
self.data = data
}
}
This works when i want to create an object
let d = ["name":"Rahul"]
let a = A(data: d)
I am trying to achieve the following but it is giving errors at the compile time.
let dArray = [["name":"Rahul"],["name":"Rahul"],["name":"Rahul"]]
let aArray = [A](data: dArray)
The following code is giving me error 'nil is the only return value permitted in an initializer'.
public extension CollectionType where Generator.Element: Decodable {
init?(data: [[String: AnyObject]]) {
var elements: [Generator.Element] = []
for d in data {
let element = Generator.Element(data: d)
if let element = element {
element.append(element)
}
}
return elements
}
}
=================================
Answer : -
public extension Array where Element: Decodable {
init?(data: [String: AnyObject]) {
var elements: [Element] = []
for d in data {
let element = Element(data: d)
if let element = element {
element.append(element)
}
}
self = elements
}
}
This will allow you to initialise using the following code
let dArray = [["name":"Rahul"],["name":"Rahul"],["name":"Rahul"]]
let aArray = [A](data: dArray)
Your error is because CollectionType is a protocol, which cannot be initialised.
Have you tried to create a helper class method to return you the collection, e.g.
func collectionWithData(data: [[String: AnyObject]]) -> [Generator.Element] {
let's define a protocol
protocol P {
init?(b: Bool)
}
as mentioned by Oliver, protocol cannot be initialized, but we still are able to define init in protocol extension
extension P {
init?(b: Bool) {
print("init defined in extension")
if b == false { return nil }
self.init(b: b)
}
}
see, that you cannot return anything from init but nil (if initialization failed)
let's define a class which conforms to our protocol
class C: P {
var b: Bool
required init(b: Bool) {
self.b = b
}
}
and see what happens in next snippet
let c1: C? = C(b: false)
let c2 = C(b: false)
dump(c1)
dump(c2)
/*
init defined in extension
- nil
▿ C #0
- b: false
*/
the same expression C(b: false) give us two different results :-). So, be careful if you define init and init? via protocol extension. If you try to define init and init? with the same parameters without protocol extension, the compiler will complain.
Is it possible to iterate over properties of a struct in Swift?
I need to register cells-reuse identifiers in a view controller that makes use of many different cell types (cells are organized in different nib files). So my idea was to put all reuse identifiers and the corresponding nib-files as static tuple-properties (reuseID, nibName) in a struct. But how can I iterate over all of them to register the cells with the tableView?
I already tried something (see my answer below). But is there a more easy way to do this, e.g. without putting every property inside an array?
Although old question, with Swift evolving this question has new answer. I think that you approach is way better for the described situation, however original question was how to iterate over struct properties, so here is my answer(works both for classes and structs)
You can use Mirror Structure Reference. The point is that after calling reflect to some object you get it's "mirror" which is pretty sparingly however still useful reflection.
So we could easily declare following protocol, where key is the name of the property and value is the actual value:
protocol PropertyLoopable
{
func allProperties() throws -> [String: Any]
}
Of course we should make use of new protocol extensions to provide default implementation for this protocol:
extension PropertyLoopable
{
func allProperties() throws -> [String: Any] {
var result: [String: Any] = [:]
let mirror = Mirror(reflecting: self)
guard let style = mirror.displayStyle where style == .Struct || style == .Class else {
//throw some error
throw NSError(domain: "hris.to", code: 777, userInfo: nil)
}
for (labelMaybe, valueMaybe) in mirror.children {
guard let label = labelMaybe else {
continue
}
result[label] = valueMaybe
}
return result
}
}
So now we can loop over the properties of any class or struct with this method. We just have to mark the class as PropertyLoopable.
In order to keep things static(as in the example) I will add also a singleton:
struct ReuseID: PropertyLoopable {
static let instance: ReuseID = ReuseID()
}
Whether singleton used or not, we could finally loop over the properties like follows:
do {
print(try ReuseID.instance.allProperties())
} catch _ {
}
And that's it with looping struct properties. Enjoy swift ;)
Using hris.to's awesome answer, I wanted to provide a Swift 3 answer that's more to the point and doesn't use singletons.
Protocol & Extension:
protocol Loopable {
func allProperties() throws -> [String: Any]
}
extension Loopable {
func allProperties() throws -> [String: Any] {
var result: [String: Any] = [:]
let mirror = Mirror(reflecting: self)
// Optional check to make sure we're iterating over a struct or class
guard let style = mirror.displayStyle, style == .struct || style == .class else {
throw NSError()
}
for (property, value) in mirror.children {
guard let property = property else {
continue
}
result[property] = value
}
return result
}
}
Example:
struct Person: Loopable {
var name: String
var age: Int
}
var bob = Person(name: "bob", age: 20)
print(try bob.allProperties())
// prints: ["name": "bob", "age": 20]
Now there's a much easier way to do this:
1: Create an Encodable protocol extension:
extension Encodable {
var dictionary: [String: Any]? {
guard let data = try? JSONEncoder().encode(self) else { return nil }
return (try? JSONSerialization.jsonObject(with: data, options: .allowFragments)).flatMap { $0 as? [String: Any] }
}
}
2: Make your struct/class conform to Encodable protocol
struct MyStruct: Encodable {...}
class MyClass: Encodable {...}
And then you can get a Dictionary representing your struct/class instance at any time:
var a: MyStruct
var b: MyClass
print(a.dictionary)
print(b.dictionary)
And then you can loop through the keys:
for (key, value) in a.dictionary { ... }
for (key, value) in b.dictionary { ... }
I made a recursive function based on #John R Perry's solution that goes deeper into properties that are objects. It also takes an parameter to limit how many levels deep it goes (default is Int.max) to help prevent stackoverflow's:
protocol Loopable {
func allProperties(limit: Int) [String: Any]
}
extension Loopable {
func allProperties(limit: Int = Int.max) [String: Any] {
return props(obj: self, count: 0, limit: limit)
}
private func props(obj: Any, count: Int, limit: Int) -> [String: Any] {
let mirror = Mirror(reflecting: obj)
var result: [String: Any] = [:]
for (prop, val) in mirror.children {
guard let prop = prop else { continue }
if limit == count {
result[prop] = val
} else {
let subResult = props(obj: val, count: count + 1, limit: limit)
result[prop] = subResult.count == 0 ? val : subResult
}
}
return result
}
}
I got rid of the check for if the object is a class or struct because that the parameter not being a class or struct is the base case of the recursive function, and it was easier to handle it manually than with errors.
Testing it:
class C {
var w = 14
}
class B: Loopable {
var x = 12
var y = "BHello"
var z = C()
static func test() -> String {
return "Test"
}
}
class A: Loopable {
var a = 1
var c = 10.0
var d = "AHello"
var e = true
var f = B()
var g = [1,2,3,4]
var h: [String: Any] = ["A": 0, "B": "Dictionary"]
var i: Int?
}
print(A().allProperties())
prints:
["e": true, "g": [1, 2, 3, 4], "f": ["z": ["w": 14], "x": 12, "y": "BHello"], "h": ["A": 0, "B": "Dictionary"], "c": 10.0, "i": nil, "d": "AHello", "a": 1]
(Dictionaries are unordered, so if you get a different order, that's why)
Here is an example of iterating over struct properties (reuse identifiers of UITableViewCells and the corresponding NIB-names) using Swifts tuple feature. This is useful if you like organizing your cells in nib files and have a UIViewController that makes use of many different cell types.
struct ReuseID {
static let prepaidRechargeCreditCell = "PrepaidRechargeCreditCell"
static let threeTitledIconCell = "ThreeTitledIconCell"
static let usageCell = "UsageCell"
static let detailsCell = "DetailsCell"
static let phoneNumberCell = "PhoneNumberCell"
static let nibNamePrepaidRechargeCreditCell = "PrepaidRechargeCreditCell"
static let nibNameThreeTitledIconCell = "IconCellWith3Titles"
static let nibNameUsageCell = "ListElementRingViewCell"
static let nibNameDetailsCell = "ListElementStandardViewCell"
static let nibNamePhoneNumberCell = "PhoneNumberCell"
static let allValuesAndNibNames = [
(ReuseID.prepaidRechargeCreditCell, ReuseID.nibNamePrepaidRechargeCreditCell),
(ReuseID.threeTitledIconCell, ReuseID.nibNameThreeTitledIconCell),
(ReuseID.usageCell, ReuseID.nibNameUsageCell),
(ReuseID.detailsCell, ReuseID.nibNameDetailsCell),
(ReuseID.phoneNumberCell, ReuseID.nibNamePhoneNumberCell)]
}
With that struct it is easy to register all cell types using a for-loop:
for (reuseID, nibName) in ReuseID.allValuesAndNibNames {
if let xibPath = NSBundle.mainBundle().pathForResource(nibName, ofType: "nib") {
let fileName = xibPath.lastPathComponent.stringByDeletingPathExtension
self.tableView.registerNib(UINib(nibName: fileName, bundle: nil), forCellReuseIdentifier: reuseID)
} else {
assertionFailure("Didn't find prepaidRechargeCreditCell 👎")
}
}
Knowing that in Swift 1.2 you could use reflect(), and since Swift 2 you can use Mirror, here is an addition to hris.to's answer for Swift 3 and 4.
protocol Loopable {
var allProperties: [String: Any] { get }
}
extension Loopable {
var allProperties: [String: Any] {
var result = [String: Any]()
Mirror(reflecting: self).children.forEach { child in
if let property = child.label {
result[property] = child.value
}
}
return result
}
}
Usage on any struct or class:
extension NSString: Loopable {}
print("hello".allProperties)
// ["_core": Swift._StringCore(_baseAddress: Optional(0x00000001157ee000), _countAndFlags: 5, _owner: nil)]
struct IdentifiersModel : Codable {
let homeReuseID: String = "Home_Reuse_ID"
let offersReuseID: String = "Offers_Reuse_ID"
let testReuseID: String = "Test_Reuse_ID"
func toDic() -> [String:Any] {
var dict = [String:Any]()
let otherSelf = Mirror(reflecting: self)
for child in otherSelf.children {
if let key = child.label {
dict[key] = child.value
}
}
return dict
}
}
Create a new instance from the struct and call toDic() function
let identifiersModel = IdentifiersModel()
print(identifiersModel.toDic())
Output:
["offersReuseID": "Offers_Reuse_ID", "testReuseID": "Test_Reuse_ID", "homeReuseID": "Home_Reuse_ID"]
I found that RPatel99's answer worked the best for me, but it did not handle the case where there as an array of Loopables inside another Loopable.
Here is a version that fixes that issue.
protocol Loopable {
func allProperties(limit: Int) -> [String: Any]
}
extension Loopable {
func allProperties(limit: Int = Int.max) -> [String: Any] {
return props(obj: self, count: 0, limit: limit)
}
private func props(obj: Any, count: Int, limit: Int) -> [String: Any] {
let mirror = Mirror(reflecting: obj)
var result: [String: Any] = [:]
for (property, value) in mirror.children {
var val = value
if let values = value as? [Loopable] {
var vals = [Any]()
for val in values {
vals.append(val.allProperties())
}
val = vals
}
guard let prop = property else { continue }
if limit == count {
result[prop] = val
} else {
let subResult = props(obj: val, count: count + 1, limit: limit)
result[prop] = subResult.count == 0 ? val : subResult
}
}
return result
}
}
class C {
var w = 14
}
class B: Loopable {
var x = 12
var y = "BHello"
var z = C()
static func test() -> String {
return "Test"
}
}
class A: Loopable {
var a = 1
var c = 10.0
var d = "AHello"
var e = B()
var f = [B(), B(), B()]
var g = [1,2,3,4]
var h: [String: Any] = ["A": 0, "B": B().allProperties()]
var i: Int?
}
print(A().allProperties())
The result I get is this
["h": ["A": 0, "B": ["z": ["w": 14], "y": "BHello", "x": 12]], "e": ["y": "BHello", "z": ["w": 14], "x": 12], "f": [["y": "BHello", "z": ["w": 14], "x": 12], ["x": 12, "z": ["w": 14], "y": "BHello"], ["y": "BHello", "x": 12, "z": ["w": 14]]], "i": nil, "g": [1, 2, 3, 4], "a": 1, "d": "AHello", "c": 10.0]
I hope someone else will find this useful.
This result could probably also be achieved by something like this
extension Array {
func removeObject<T where T : Equatable>(object: T) {
var index = find(self, object)
self.removeAtIndex(index)
}
}
However, I get an error on var index = find(self, object)
'T' is not convertible to 'T'
I also tried with this method signature: func removeObject(object: AnyObject), however, I get the same error:
'AnyObject' is not convertible to 'T'
What is the proper way to do this?
As of Swift 2, this can be achieved with a protocol extension method.
removeObject() is defined as a method on all types conforming
to RangeReplaceableCollectionType (in particular on Array) if
the elements of the collection are Equatable:
extension RangeReplaceableCollectionType where Generator.Element : Equatable {
// Remove first collection element that is equal to the given `object`:
mutating func removeObject(object : Generator.Element) {
if let index = self.indexOf(object) {
self.removeAtIndex(index)
}
}
}
Example:
var ar = [1, 2, 3, 2]
ar.removeObject(2)
print(ar) // [1, 3, 2]
Update for Swift 2 / Xcode 7 beta 2: As Airspeed Velocity noticed
in the comments, it is now actually possible to write a method on a generic type that is more restrictive on the template, so the method
could now actually be defined as an extension of Array:
extension Array where Element : Equatable {
// ... same method as above ...
}
The protocol extension still has the advantage of being applicable to
a larger set of types.
Update for Swift 3:
extension Array where Element: Equatable {
// Remove first collection element that is equal to the given `object`:
mutating func remove(object: Element) {
if let index = index(of: object) {
remove(at: index)
}
}
}
Update for Swift 5:
extension Array where Element: Equatable {
/// Remove first collection element that is equal to the given `object` or `element`:
mutating func remove(element: Element) {
if let index = firstIndex(of: element) {
remove(at: index)
}
}
}
You cannot write a method on a generic type that is more restrictive on the template.
NOTE: as of Swift 2.0, you can now write methods that are more restrictive on the template. If you have upgraded your code to 2.0, see other answers further down for new options to implement this using extensions.
The reason you get the error 'T' is not convertible to 'T' is that you are actually defining a new T in your method that is not related at all to the original T. If you wanted to use T in your method, you can do so without specifying it on your method.
The reason that you get the second error 'AnyObject' is not convertible to 'T' is that all possible values for T are not all classes. For an instance to be converted to AnyObject, it must be a class (it cannot be a struct, enum, etc.).
Your best bet is to make it a function that accepts the array as an argument:
func removeObject<T : Equatable>(object: T, inout fromArray array: [T]) {
}
Or instead of modifying the original array, you can make your method more thread safe and reusable by returning a copy:
func arrayRemovingObject<T : Equatable>(object: T, fromArray array: [T]) -> [T] {
}
As an alternative that I don't recommend, you can have your method fail silently if the type stored in the array cannot be converted to the the methods template (that is equatable). (For clarity, I am using U instead of T for the method's template):
extension Array {
mutating func removeObject<U: Equatable>(object: U) {
var index: Int?
for (idx, objectToCompare) in enumerate(self) {
if let to = objectToCompare as? U {
if object == to {
index = idx
}
}
}
if(index != nil) {
self.removeAtIndex(index!)
}
}
}
var list = [1,2,3]
list.removeObject(2) // Successfully removes 2 because types matched
list.removeObject("3") // fails silently to remove anything because the types don't match
list // [1, 3]
Edit To overcome the silent failure you can return the success as a bool:
extension Array {
mutating func removeObject<U: Equatable>(object: U) -> Bool {
for (idx, objectToCompare) in self.enumerate() { //in old swift use enumerate(self)
if let to = objectToCompare as? U {
if object == to {
self.removeAtIndex(idx)
return true
}
}
}
return false
}
}
var list = [1,2,3,2]
list.removeObject(2)
list
list.removeObject(2)
list
briefly and concisely:
func removeObject<T : Equatable>(object: T, inout fromArray array: [T])
{
var index = find(array, object)
array.removeAtIndex(index!)
}
After reading all the above, to my mind the best answer is:
func arrayRemovingObject<U: Equatable>(object: U, # fromArray:[U]) -> [U] {
return fromArray.filter { return $0 != object }
}
Sample:
var myArray = ["Dog", "Cat", "Ant", "Fish", "Cat"]
myArray = arrayRemovingObject("Cat", fromArray:myArray )
Swift 2 (xcode 7b4) array extension:
extension Array where Element: Equatable {
func arrayRemovingObject(object: Element) -> [Element] {
return filter { $0 != object }
}
}
Sample:
var myArray = ["Dog", "Cat", "Ant", "Fish", "Cat"]
myArray = myArray.arrayRemovingObject("Cat" )
Swift 3.1 update
Came back to this now that Swift 3.1 is out. Below is an extension which provides exhaustive, fast, mutating and creating variants.
extension Array where Element:Equatable {
public mutating func remove(_ item:Element ) {
var index = 0
while index < self.count {
if self[index] == item {
self.remove(at: index)
} else {
index += 1
}
}
}
public func array( removing item:Element ) -> [Element] {
var result = self
result.remove( item )
return result
}
}
Samples:
// Mutation...
var array1 = ["Cat", "Dog", "Turtle", "Cat", "Fish", "Cat"]
array1.remove("Cat")
print(array1) // ["Dog", "Turtle", "Socks"]
// Creation...
let array2 = ["Cat", "Dog", "Turtle", "Cat", "Fish", "Cat"]
let array3 = array2.array(removing:"Cat")
print(array3) // ["Dog", "Turtle", "Fish"]
With protocol extensions you can do this,
extension Array where Element: Equatable {
mutating func remove(object: Element) {
if let index = indexOf({ $0 == object }) {
removeAtIndex(index)
}
}
}
Same functionality for classes,
Swift 2
extension Array where Element: AnyObject {
mutating func remove(object: Element) {
if let index = indexOf({ $0 === object }) {
removeAtIndex(index)
}
}
}
Swift 3
extension Array where Element: AnyObject {
mutating func remove(object: Element) {
if let index = index(where: { $0 === object }) {
remove(at: index)
}
}
}
But if a class implements Equatable it becomes ambiguous and the compiler gives an throws an error.
With using protocol extensions in swift 2.0
extension _ArrayType where Generator.Element : Equatable{
mutating func removeObject(object : Self.Generator.Element) {
while let index = self.indexOf(object){
self.removeAtIndex(index)
}
}
}
what about to use filtering? the following works quite well even with [AnyObject].
import Foundation
extension Array {
mutating func removeObject<T where T : Equatable>(obj: T) {
self = self.filter({$0 as? T != obj})
}
}
Maybe I didn't understand the question.
Why wouldn't this work?
import Foundation
extension Array where Element: Equatable {
mutating func removeObject(object: Element) {
if let index = self.firstIndex(of: object) {
self.remove(at: index)
}
}
}
var testArray = [1,2,3,4,5,6,7,8,9,0]
testArray.removeObject(object: 6)
let newArray = testArray
var testArray2 = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]
testArray2.removeObject(object: "6")
let newArray2 = testArray2
No need to extend:
var ra = [7, 2, 5, 5, 4, 5, 3, 4, 2]
print(ra) // [7, 2, 5, 5, 4, 5, 3, 4, 2]
ra.removeAll(where: { $0 == 5 })
print(ra) // [7, 2, 4, 3, 4, 2]
if let i = ra.firstIndex(of: 4) {
ra.remove(at: i)
}
print(ra) // [7, 2, 3, 4, 2]
if let j = ra.lastIndex(of: 2) {
ra.remove(at: j)
}
print(ra) // [7, 2, 3, 4]
There is another possibility of removing an item from an array without having possible unsafe usage, as the generic type of the object to remove cannot be the same as the type of the array. Using optionals is also not the perfect way to go as they are very slow. You could therefore use a closure like it is already used when sorting an array for example.
//removes the first item that is equal to the specified element
mutating func removeFirst(element: Element, equality: (Element, Element) -> Bool) -> Bool {
for (index, item) in enumerate(self) {
if equality(item, element) {
self.removeAtIndex(index)
return true
}
}
return false
}
When you extend the Array class with this function you can remove elements by doing the following:
var array = ["Apple", "Banana", "Strawberry"]
array.removeFirst("Banana") { $0 == $1 } //Banana is now removed
However you could even remove an element only if it has the same memory address (only for classes conforming to AnyObject protocol, of course):
let date1 = NSDate()
let date2 = NSDate()
var array = [date1, date2]
array.removeFirst(NSDate()) { $0 === $1 } //won't do anything
array.removeFirst(date1) { $0 === $1 } //array now contains only 'date2'
The good thing is, that you can specify the parameter to compare. For example when you have an array of arrays, you can specify the equality closure as { $0.count == $1.count } and the first array having the same size as the one to remove is removed from the array.
You could even shorten the function call by having the function as mutating func removeFirst(equality: (Element) -> Bool) -> Bool, then replace the if-evaluation with equality(item) and call the function by array.removeFirst({ $0 == "Banana" }) for example.
Using indexOf instead of a for or enumerate:
extension Array where Element: Equatable {
mutating func removeElement(element: Element) -> Element? {
if let index = indexOf(element) {
return removeAtIndex(index)
}
return nil
}
mutating func removeAllOccurrencesOfElement(element: Element) -> Int {
var occurrences = 0
while true {
if let index = indexOf(element) {
removeAtIndex(index)
occurrences++
} else {
return occurrences
}
}
}
}
I finally ended up with following code.
extension Array where Element: Equatable {
mutating func remove<Element: Equatable>(item: Element) -> Array {
self = self.filter { $0 as? Element != item }
return self
}
}
Your problem is T is not related to the type of your array in anyway for example you could have
var array = [1,2,3,4,5,6]
array.removeObject(object:"four")
"six" is Equatable, but its not a type that can be compared to Integer, if you change it to
var array = [1,2,3,4,5,6]
extension Array where Element : Equatable {
mutating func removeObject(object: Element) {
filter { $0 != object }
}
}
array.removeObject(object:"four")
it now produces an error on calling removeObject for the obvious reason its not an array of strings, to remove 4 you can just
array.removeObject(object:4)
Other problem you have is its a self modifying struct so the method has to be labeled as so and your reference to it at the top has to be a var
Implementation in Swift 2:
extension Array {
mutating func removeObject<T: Equatable>(object: T) -> Bool {
var index: Int?
for (idx, objectToCompare) in self.enumerate() {
if let toCompare = objectToCompare as? T {
if toCompare == object {
index = idx
break
}
}
}
if(index != nil) {
self.removeAtIndex(index!)
return true
} else {
return false
}
}
}
I was able to get it working with:
extension Array {
mutating func removeObject<T: Equatable>(object: T) {
var index: Int?
for (idx, objectToCompare) in enumerate(self) {
let to = objectToCompare as T
if object == to {
index = idx
}
}
if(index) {
self.removeAtIndex(index!)
}
}
}