Error while using index method of Array class - arrays

I have created a custom class MyArray for practice and learning. I have created a few methods inside that class and an internal array. I am facing an error while using the index(of: ) method on the internal array defined inside the class. Code of my class is as below:
public class MyArray<Element> {
private var factorialNumber: Double = 0
private var arr: [Element] = []
internal var instance: MyArray?
private init() {}
public func removeElement(_ item: Element) -> [Element] {
var found = true
while found {
if arr.contains(item) { // ERROR: Missing argument label '"where:" in call
let index = arr.index(of: item) // Error: cannot invoke index with an argument list of type (of: Element)
arr.remove(at: index!)
} else {
found = false
}
}
return arr
}
public func removeFirstOccurance(of value: Element) -> [Element] {
let index : Int = arr.index(of: value)
arr.remove(at: index!) // ERROR: Cannot force wrap value of non optional type Int
return arr
}
}

Related

swift 5: how to check array generic type?

var array: Array<Int>? = nil
var arrayType: Any.Type = type(of: array)
print("type:\(arrayType)")
I got printed:
type:Optional<Array<Int>>
then, how can i get the type Int from arrayType?
You may not understand why I did this. The actual situation is:
I have a bean, like this:
protocol Initializable {
init()
}
class MyBean1: Initializable {
required init() {}
var property1: Int?
var property2: String?
}
class MyBean2: Initializable {
required init() {}
var beans: Array<MyBean1>?
}
I have json data like this:
{beans:[{"property1":1,"property2":"string1"},{"property1":2,"property2":"string2"}]}
I want automatic create object and set the values.
I use the Runtime(A Swift Runtime library for viewing type info, and the dynamic getting and setting of properties.) Framework to mirror and set properties.
I extend the TypeInfo:
extension TypeInfo {
func properties() -> [String] {
var properties: [String] = []
for property in self.properties {
properties.append(property.name)
}
return properties
}
}
I want create object from json string:
static func fromJson<Result: Initializable>(json: String, type: Result.Type) -> Result {
var result: Initializable = Result.init()
if let dictionary = Dictionary<String, Any>.from(json: json) {
if let info: TypeInfo = try? typeInfo(of: type(of: result)) {
let properties = info.properties()
for (key, value) in dictionary {
if properties.contains(key) {
if let property: PropertyInfo = try? info.property(named: key) {
print("\(key):\(property.type)")
}
}
}
}
}
return result as! Result
}
I got print:
beans:Optional<Array<MyBean1>>
the property.type type is Any.Type.
I want get the type MyBean1 and create MyBean1's object from property.type.
Now i use Bundle.main.classNamed to get the generic type.
TypeName got from substring
var typeName = "\(property.type)" // Optional<Array<MyBean1>>
if let range = typeName.range(of: "Optional<") {
typeName = typeName.replacingCharacters(in: range, with: "")
typeName = String(typeName[typeName.startIndex..<(typeName.index(before: typeName.endIndex))])
}
print("typeName:\(typeName)") // Array<MyBean1>
if let range = typeName.range(of: "Array<") {
typeName = typeName.replacingCharacters(in: range, with: "")
typeName = String(typeName[typeName.startIndex..<(typeName.index(before: typeName.endIndex))])
print("typeName:\(typeName)") // MyBean1
if let namespace = Bundle.main.infoDictionary?["CFBundleExecutable"] as? String {
let clazz: AnyClass? = Bundle.main.classNamed("\(namespace).\(typeName)")
if let initableType = clazz as? Initializable.Type {
var beans = Array<Any>()
for item in array {
var bean = initableType.init()
// set bean properties
beans.append(bean)
}
}
}
}

Array of funcs in a Swift class instance

How can I get an array of funcs prefixed with a certain name from a Swift class instance without hardcoding those funcs' names?
e.g.
class Dialog {
init() {
}
func stepOne(session: Session) {
...
}
func stepTwo(session: Session) {
...
}
func stepThree(session: Session) {
...
}
func someOtherFunc() {
...
}
func steps() -> [(Session) -> Void] {
// should return [stepOne, stepTwo, stepThree];
}
}
The functions have to come from somewhere. They don't necessarily have to be defined in Dialog; they can be local variables inside func steps(). For instance:
func steps() -> [(Session) -> Void] {
var allSteps: [(Session) -> Void] = []
for i in 0..<3 {
let currentStep: (Session) -> Void = { session in
print("Executing step \(i)")
}
allSteps.append(currentStep)
}
return allSteps
}

How to sort a typed array in swift?

I built a custom class which holds an "internal" array and offers some useful methods.
class ArrayList<T> {
private var array : Array<T>
public init() {
array = Array<T>()
}
public func add(element : T) {
array.append(element)
}
public func size() -> Int {
return array.count
}
...
}
Ok, that works fine for me so far.
But now I also want to have a method to sort the array. What I already have is the following:
public func sort(comparator : ?) {
array = array.sort(comparator)
}
The question mark stands for the parameter type and that is my problem: Which type must the parameter have? I read something about #noescape<,> but I can't get it to work!
I'm using Swift 2.2.
The easiest way is the use the standard closure
public func sort(comparator : (T, T) -> Bool) {
array.sortInPlace(comparator)
}
and constrain the generic type to the Comparable protocol
class ArrayList<T : Comparable>
Then you can use this code
let arrayList = ArrayList<Int>()
arrayList.add(5)
arrayList.add(12)
arrayList.add(10)
arrayList.add(2)
arrayList.sort { $0 < $1 }
print(arrayList.array) // [2, 5, 10, 12]

How can I make a class property array be a heterogeneous array of a generic type?

Here's what I want. I'm writing a very simple event dispatcher (click that link to see my code). It was working fine when I only had the listen() and the fire() method. This is how you could use it:
struct UserHasBirthday: Event {
let name: String
init(name: String) {
self.name = name
}
}
let events = TestDispatcher()
events.listen {
(event: UserHasBirthday) in
print("Happy birthday \(event.name)!")
}
events.fire( UserHasBirthday(name: "John Doe") )
That's all well and good, but now I wanted to add the feature that you could push events to a queue and then later fire them all at once. That's why I added the push and flush methods.
Now the problem is that in the flush() method I need to be able to downcast the generic Event type to the specific event type that was given. Otherwise the fire() method doesn't work.
So I thought, maybe I could save the type information in the same array as the event itself. As you can see I tried to do that with a tuple. Unfortunately it doesn't work like that.
I think that if I could find a way to make the variable pushedEvents accept a generic type like so: var pushedEvents = Array<E: Event>() then it could work. But the only way I know to do that is to assign that generic to the whole class like so: class TestDispatcher<E: Event> { }, but then every instance of that class can only be used for one specific type of event and I definitely don't want that.
Does anybody know some kind of way to make this work?
This guy on reddit gave me the solution by using a so-called type-erasure pattern (I didn't know about that pattern).
I edited his code to meet my needs more and this is what I have now:
public protocol Event {}
public protocol ErasedListener {
func matches(eventType: Event.Type) -> Bool
func dispatchIfMatches(event: Event)
}
public struct Listener<T: Event>: ErasedListener {
let dispatch: T -> Void
public func matches(eventType: Event.Type) -> Bool {
return matches(String(eventType))
}
func matches(eventType: String) -> Bool {
return eventType == String(T.self)
}
public func dispatchIfMatches(event: Event) {
if matches(String(event.dynamicType)) {
dispatch(event as! T)
}
}
}
public protocol Dispatcher {
func listen<E: Event>(listener: E -> Void)
func fire(event: Event)
func queue<E: Event>(event: E)
func flushQueueOf<E: Event>(eventType: E.Type)
func flushQueue()
func forgetListenersFor<E: Event>(event: E.Type)
func emptyQueueOf<E: Event>(eventType: E.Type)
func emptyQueue()
}
public class MyDispatcher: Dispatcher {
var listeners = [ErasedListener]()
var queuedEvents = [Event]()
public init() {}
public func listen<E: Event>(listener: E -> Void) {
let concreteListener = Listener(dispatch: listener)
listeners.append(concreteListener as ErasedListener)
}
public func fire(event: Event) {
for listener in listeners {
listener.dispatchIfMatches(event)
}
}
public func queue<E: Event>(event: E) {
queuedEvents.append(event)
}
public func flushQueue() {
for event in queuedEvents {
fire(event)
}
emptyQueue()
}
public func emptyQueue() {
queuedEvents = []
}
public func flushQueueOf<E: Event>(eventType: E.Type) {
for event in queuedEvents where String(event.dynamicType) == String(eventType) {
fire(event)
}
emptyQueueOf(eventType)
}
public func forgetListenersFor<E: Event>(eventType: E.Type) {
listeners = listeners.filter { !$0.matches(eventType) }
}
public func emptyQueueOf<E: Event>(eventType: E.Type) {
queuedEvents = queuedEvents.filter { String($0.dynamicType) != String(eventType) }
}
}
Example usage
struct UserDied: Event {
var name: String
}
class UserWasBorn: Event {
let year: Int
init(year: Int) {
self.year = year
}
}
// you can use both classes and structs as events as you can see
let daveDied = UserDied(name: "Dave")
let bartWasBorn = UserWasBorn(year: 2000)
var events = MyDispatcher()
events.listen {
(event: UserDied) in
print(event.name)
}
events.listen {
(event: UserWasBorn) in
print(event.year)
}
events.queue(daveDied)
events.queue(UserWasBorn(year: 1990))
events.queue(UserWasBorn(year: 2013))
events.queue(UserDied(name: "Evert"))
// nothing is fired yet, do whatever you need to do first
events.flushQueue()
/*
This prints:
Dave
1990
2013
Evert
*/
// You could also have flushed just one type of event, like so:
events.flushQueueOf(UserDied)
// This would've printed Dave and Evert,
// but not the year-numbers of the other events
The problem is that Swift doesn't allow type conversion to metatypes.
One workaround is to include all types that conform to Event (at least those you will use in your Dispatcher) in a switch case in the flush() function of your TestDispatcher class. It isn't as versatile as the functionality I believe you're looking for, and as you've shown with your own answer, type erasure is the way to here. I'll leave my original answer intact however, as it explains why your original approach of attempting to cast to metatypes didn't work.
public protocol Event {}
public enum Listener<E: Event> {
public typealias T = E -> ()
}
public protocol Dispatcher {
func listen<E: Event>(listener: Listener<E>.T)
func fire<E: Event>(event: E)
func push<E: Event>(event: E)
func flush()
}
//
public class TestDispatcher: Dispatcher {
var listeners = [String:[Any]]()
var pushedEvents = [Event]()
public init() {}
public func listen<E: Event>(listener: Listener<E>.T) {
var listeners = self.listeners[String(E.self)] ?? []
listeners += [listener] as [Any]
self.listeners[String(E.self)] = listeners
}
public func fire<E: Event>(event: E) {
listeners[String(E.self)]?.forEach {
let f = $0 as! Listener<E>.T
f(event)
}
}
public func push<E: Event>(event: E) {
pushedEvents = pushedEvents + [event]
}
/* Include a switch case over all types conforming to Event ... */
public func flush() {
for event in pushedEvents {
switch event {
case let ev as UserHasBirthday: fire(ev)
case let ev as UserWonTheLottery: fire(ev)
case _: print("Unknown event type.")
}
}
}
}
Example usage:
struct UserHasBirthday: Event {
let name: String
init(name: String) {
self.name = name
}
}
struct UserWonTheLottery: Event {
let name: String
let amount: Int
init(name: String, amount: Int) {
self.name = name
self.amount = amount
}
}
let events = TestDispatcher()
events.listen {
(event: UserHasBirthday) in
print("Happy birthday \(event.name)!")
}
events.listen {
(event: UserWonTheLottery) in
print("Congratulations \(event.name) for winning \(event.amount)!")
}
events.push(UserHasBirthday(name: "John Doe"))
events.push(UserHasBirthday(name: "Jane Doe"))
events.push(UserWonTheLottery(name: "Jane Doe", amount: 42000))
events.flush()
/* Happy birthday John Doe!
Happy birthday Jane Doe!
Congratulations Jane Doe for winning 42000! */

How to implement a selectable array struct in swift?

I would like to implement an array struct which can mark a single element is able to be as selected. Thus, that element can be easily accessed.
I am creating a wrapper class around Array struct. Is there any good way to delegate Array methods to my SelectableArray's internal array?
Or is there other better way to do it?
class SelectableArray<Element: Comparable> {
let array = Array<Element>()
private var selectedIndex: Int? = .None
var selectedElement: Element? {
guard let index = selectedIndex else {
return .None
}
return array[index]
}
func select(index: Int) {
selectedIndex = array.indices.contains(index) ? index : .None
}
func select(element: Element) {
selectedIndex = array.indexOf(element)
}
}
Just create an append method for your wrapper class and change array to a var from a let:
class SelectableArray<Element: Comparable> {
var array = Array<Element>()
private var selectedIndex: Int? = .None
// other functions...
func append(element: Element) {
self.array.append(element)
}
}

Resources