I am trying to display only the cells with the same title as the searchbar text. I thought that I had have a few methodes, but none of them seem to work.
Methode 1:
func Search() {
Aanbiedingen_bieren_Filter = Aanbiedingen_bieren_Filter.filter {SearchBar.text!.lowercased() == $0.Title.lowercased() }
tableView.reloadData()
}
Methode 2:
func Search() {
for Json in Aanbiedingen_bieren_Filter {
let Naam = Json.Title.lowercased()
if SearchBar.text!.lowercased().contains(Naam) {
Aanbiedingen_bieren_Filter.append(Json)
}
}
tableView.reloadData
}
When Searchbar text change run Search()
func searchBarSearchButtonClicked(_ SearchBar: UISearchBar) {
Search()
}
func searchBar(_ SearchBar: UISearchBar, textDidChange searchText: String) {
Search()
}
Struct:
struct SheetJS: Codable {
var SheetJS: [Aanbiedingen_bier]
init(SheetJS: [Aanbiedingen_bier]) {
self.SheetJS = SheetJS
}
}
struct Aanbiedingen_bier: Codable {
let Title: String
init(Title: String) {
self.Title = Title
}
}
Json:
"SheetJS": [
{
"Logo_Image": "Grolsch Premium Pilsener"
},//Some more data
]
When I run this code it will give me an empty Aanbiedingen_bier_Filter back. I am not sure why this is.
Neither of your tests is what you want:
SearchBar.text!.lowercased().contains(Naam)
SearchBar.text!.lowercased() == $0.Title.lowercased
What you want to know is whether the title contains the search text, not the other way round or whether they are identical (very unlikely).
Checked the doc, but not talks about many details of implementation. Wondering if for a large array, does it perform in concurrent way?
The map implementation of Array specifically doesn't perform any multithreading, but there's nothing that says you couldn't make a concurrent implementation. Here's one that's generalized to work with any Sequence:
import Dispatch
class SharedSynchronizedArray<T> {
var array = [T]()
let operationQueue = DispatchQueue(label: "SharedSynchronizedArray")
func append(_ newElement: T) {
operationQueue.sync {
array.append(newElement)
}
}
}
public struct ConcurrentSequence<Base, Element>: Sequence
where Base: Sequence, Element == Base.Iterator.Element {
let base: Base
public func makeIterator() -> Base.Iterator {
return base.makeIterator()
}
public func map<T>(_ transform: #escaping (Element) -> T) -> [T] {
let group = DispatchGroup()
let resultsStorageQueue = DispatchQueue(label: "resultStorageQueue")
let results = SharedSynchronizedArray<T>()
let processingQueue = DispatchQueue(
label: "processingQueue",
attributes: [.concurrent]
)
for element in self {
group.enter()
print("Entered DispatchGroup for \(element)")
var result: T?
let workItem = DispatchWorkItem{ result = transform(element) }
processingQueue.async(execute: workItem)
resultsStorageQueue.async {
workItem.wait()
guard let unwrappedResult = result else {
fatalError("The work item was completed, but the result wasn't set!")
}
results.append(unwrappedResult)
group.leave()
print("Exited DispatchGroup for \(element)")
}
}
print("Started Waiting on DispatchGroup")
group.wait()
print("DispatchGroup done")
return results.array
}
}
public extension Sequence {
public var parallel: ConcurrentSequence<Self, Iterator.Element> {
return ConcurrentSequence(base: self)
}
}
print("Start")
import Foundation
let input = Array(0..<100)
let output: [Int] = input.parallel.map {
let randomDuration = TimeInterval(Float(arc4random()) / Float(UInt32.max))
Thread.sleep(forTimeInterval: randomDuration)
print("Transforming \($0)")
return $0 * 2
}
print(output)
// print(output.parallel.filter{ $0 % 3 == 0 })
print("Done")
I'm writing a Swift extension that checks if two or more CGPoints in array have the same coordinates. Having this code I can check all points in array.
But how to check just several elements (not all)?
Here's the extension...
import Foundation
extension Array where Element : Equatable {
func equalCoordinates() -> Bool {
if let firstElement = first {
return dropFirst().contains { $0 == firstElement }
}
return true
}
}
If two (or more) red CGPoints have identical coordinates they must be turned into green ones.
...and a code in ViewController using equalCoordinates() method:
func drawn() {
let colorArray = array.map { $0.pointCoord()[0] }
for dot in array {
for cPoint in dot.pointCoord() {
if colorArray.equalCoordinates() {
let altColor = dot.alternativePointColour()
draw(cPoint, color: altColor)
} else {
let color = dot.pointColour()
draw(cPoint, color: color)
}
}
}
}
...........
Swift.print(colorArray.equalCoordinates())
...........
With absolutely no concern given to efficiency (that can be improved depending on the size of your data), this is how I'd probably go about it. Each piece is pretty simple, so you should be able to adapt it to a wide variety of different outputs (if you prefer something other than IndexSet for instance).
import Foundation
import CoreGraphics
// We could put this on Collection rather than Array, but then we'd have to rewrite
// IndexSet on generic indices or use [Index].
extension Array where Element : Equatable {
func uniqueElements() -> [Element] {
// This is O(n^2), but it's hard to beat that without adding either
// Hashable (for Set) or Comparable (to pre-sort) to the requirements,
// neither of which CGPoints have by default.
var uniqueElements: [Element] = []
for element in self {
if !uniqueElements.contains(element) {
uniqueElements.append(element)
}
}
return uniqueElements
}
func indexSet(of element: Element) -> IndexSet {
var indices = IndexSet()
for (index, member) in enumerated() {
if element == member {
indices.insert(index)
}
}
return indices
}
func indexSetsGroupedByEquality() -> [(element: Element, indexSet: IndexSet)] {
return uniqueElements().map { element in (element, indexSet(of: element)) }
}
func indexSetsOfCollidingElements() -> [IndexSet] {
func hasCollisions(_: Element, indexSet: IndexSet) -> Bool { return indexSet.count > 1 }
return indexSetsGroupedByEquality()
.filter(hasCollisions)
.map { $0.indexSet }
}
}
let points = [
CGPoint(x:1,y:1),
CGPoint(x:2,y:1),
CGPoint(x:1,y:1),
CGPoint(x:3,y:1),
CGPoint(x:2,y:1),
]
print(points.indexSetsOfCollidingElements().map(Array.init))
// [[0, 2], [1, 4]]
Swift 2.2 version
extension Array where Element : Equatable {
func uniqueElements() -> [Element] {
var uniqueElements: [Element] = []
for element in self {
if !uniqueElements.contains(element) {
uniqueElements.append(element)
}
}
return uniqueElements
}
func indexSet(of element: Element) -> NSIndexSet {
let indices = NSIndexSet()
for (index, member) in enumerate() {
if element == member {
indices.insertValue(index, inPropertyWithKey: "")
}
}
return indices
}
func indexSetsGroupedByEquality() -> [(element: Element,
indexSet: NSIndexSet)] {
return uniqueElements().map { element in
(element, indexSet(of: element))
}
}
func indexSetsOfCollidingElements() -> [NSIndexSet] {
func hasCollisions(_: Element, indexSet: NSIndexSet) -> Bool {
return indexSet.count > 0
}
return indexSetsGroupedByEquality().filter(hasCollisions)
.map { $0.indexSet }
}
}
I'm trying to write a light observer class in Swift (currently Swift 2). The idea is to use it within an Entity Component system, as a means for the components to communicate with one-another without being coupled together.
The problem I'm having is that all types of data could be communicated, a CGVector, an NSTimeInterval and so on. This means that the method being passed could have all kinds of type signatures (CGVector) -> Void, () -> Void etc.
I'd like to be able to store these varying signatures in an array, but still have some type safety. My thinking is that the type for the array would be (Any) -> Void or perhaps (Any?) -> Void, so that I can at least ensure that it contains methods. But I'm having trouble passing methods in this way: Cannot convert value of type '(CGVector) -> ()' to expected argument type '(Any) -> ()'.
First attempt:
//: Playground - noun: a place where people can play
import Cocoa
import Foundation
enum EventName: String {
case input, update
}
struct Binding{
let listener: Component
let action: (Any) -> ()
}
class EventManager {
var events = [EventName: [Binding]]()
func add(name: EventName, event: Binding) {
if var eventArray = events[name] {
eventArray.append(event)
} else {
events[name] = [event]
}
}
func dispatch(name: EventName, argument: Any) {
if let eventArray = events[name] {
for element in eventArray {
element.action(argument)
}
}
}
func remove(name: EventName, listener: Component) {
if var eventArray = events[name] {
eventArray = eventArray.filter(){ $0.listener.doc != listener.doc }
}
}
}
// Usage test
//Components
protocol Component {
var doc: String { get }
}
class Input: Component {
let doc = "InputComponent"
let eventManager: EventManager
init(eventManager: EventManager) {
self.eventManager = eventManager
}
func goRight() {
eventManager.dispatch(.input, argument: CGVector(dx: 10, dy: 0) )
}
}
class Movement: Component {
let doc = "MovementComponent"
func move(vector: CGVector) {
print("moved \(vector)")
}
}
class Physics: Component {
let doc = "PhysicsComponent"
func update(time: NSTimeInterval){
print("updated at \(time)")
}
}
class someClass {
//events
let eventManager = EventManager()
// components
let inputComponent: Input
let moveComponent = Movement()
init() {
inputComponent = Input(eventManager: eventManager)
let inputBinding = Binding(listener: moveComponent, action: moveComponent.move) // ! Cannot convert value of type '(CGVector) -> ()' to expected argument type '(Any) -> ()'
eventManager.add(.input, event: inputBinding)
}
}
let someInstance = someClass()
someInstance.inputComponent.goRight()
Throws the error Cannot convert value of type '(CGVector) -> ()' to expected argument type '(Any) -> ()'.
Second attempt
If I genericize the Binding struct to recognise different types of arguments I have a bit more luck. This version basically works, but the array holding the methods is now [Any] ( I'm not sure whether it's the attempt to cast Any back to the Binding struct that is causing the slightly odd error below Binary operator '!=' cannot be applied to two 'String' operands):
struct Binding<Argument>{
let listener: Component
let action: (Argument) -> ()
}
class EventManager {
var events = [EventName: [Any]]()
func add(name: EventName, event: Any) {
if var eventArray = events[name] {
eventArray.append(event)
} else {
events[name] = [event]
}
}
func dispatch<Argument>(name: EventName, argument: Argument) {
if let eventArray = events[name] {
for element in eventArray {
(element as! Binding<Argument>).action(argument)
}
}
}
func remove(name: EventName, listener: Component) {
if var eventArray = events[name] {
// eventArray = eventArray.filter(){ ($0 as! Binding).listener.doc != listener.doc } //Binary operator '!=' cannot be applied to two 'String' operands
}
}
}
Is there a way to do this and have the array hold methods of varying type signatures, something like [(Any?) -> ()] ?
Attempt 3...
Reading around, eg here http://www.klundberg.com/blog/capturing-objects-weakly-in-instance-method-references-in-swift/ it seems that my approach above will lead to strong reference cycles, and that what I need to do is pass the static method eg Movement.move rather than moveComponent.move. So the type signature I would be storing would actually be (Component) -> (Any?) -> Void rather than (Any?) -> Void. But my question still stands, I still would like to be able to store an array of these static methods with a bit more type-safety than just [Any].
One approach to casting the parameters of a closure, suggested in Mike Ash's blog that Casey Fleser linked to, is to "recurry"(?) it.
A genericised Binding class:
private class Binding<Argument>{
weak var listener: AnyObject?
let action: AnyObject -> Argument -> ()
init(listener: AnyObject, action: AnyObject -> Argument -> ()) {
self.listener = listener
self.action = action
}
func invoke(data: Argument) -> () {
if let this = listener {
action(this)(data)
}
}
}
And the event manager, without the recurrying:
class EventManager {
var events = [EventName: [AnyObject]]()
func add<T: AnyObject, Argument>(name: EventName, listener: T, action: T -> Argument -> Void) {
let binding = Binding(listener: listener, action: action) //error: cannot convert value of type 'T -> Argument -> Void' to expected argument type 'AnyObject -> _ -> ()'
if var eventArray = events[name] {
eventArray.append(binding)
} else {
events[name] = [binding]
}
}
func dispatch<Argument>(name: EventName, argument: Argument) {
if let eventArray = events[name] {
for element in eventArray {
(element as! Binding<Argument>).invoke(argument)
}
}
}
func remove(name: EventName, listener: Component) {
if var eventArray = events[name] {
eventArray = eventArray.filter(){ $0 !== listener }
}
}
}
This still produces the same error, of not being able to cast to AnyObject:
error: cannot convert value of type 'T -> Argument -> Void' to expected argument type 'AnyObject -> _ -> ()'.
Bu if we call the first part of the curried function, and enclose it within a new closure (I don't know if this has a name, I'm calling it "recurrying"), like this: action: { action($0 as! T) } then it all works (technique taken from Mike Ash). I guess this is a bit of a hack, in that Swift type safety is being circumvented.
I also don't really understand the error message: it's saying it can't convert T to AnyObject, but then accepts casting to T?
EDIT: updated with the complete code so far
edit2: corrected how events are appended
edit3: removing events now works
//: Playground - noun: a place where people can play
import Cocoa
import Foundation
enum EventName: String {
case input, update
}
private class Binding<Argument>{
weak var listener: AnyObject?
let action: AnyObject -> Argument -> ()
init(listener: AnyObject, action: AnyObject -> Argument -> ()) {
self.listener = listener
self.action = action
}
func invoke(data: Argument) -> () {
if let this = listener {
action(this)(data)
}
}
}
class EventManager {
var events = [EventName: [AnyObject]]()
func add<T: AnyObject, Argument>(name: EventName, listener: T, action: T -> Argument -> Void) {
let binding = Binding(listener: listener, action: { action($0 as! T) }) //
if events[name]?.append(binding) == nil {
events[name] = [binding]
}
}
func dispatch<Argument>(name: EventName, argument: Argument) {
if let eventArray = events[name] {
for element in eventArray {
(element as! Binding<Argument>).invoke(argument)
}
}
}
func remove<T: AnyObject, Argument>(name: EventName, listener: T, action: T -> Argument -> Void) {
events[name]? = events[name]!.filter(){ ( $0 as! Binding<Argument>).listener !== listener }
}
}
// Usage test
//Components
class Component {
weak var events: EventManager?
let doc: String
init(doc: String){
self.doc = doc
}
}
class Input: Component {
init() {
super.init(doc: "InputComponent")
}
func goRight() {
events?.dispatch(.input, argument: CGVector(dx: 10, dy: 0) )
}
func goUp() {
events?.dispatch(.input, argument: CGVector(dx: 0, dy: -5) )
}
}
class Movement: Component {
init() {
super.init(doc: "MovementComponent")
}
func move(vector: CGVector) {
print("moved \(vector)")
}
}
class Physics: Component {
init() {
super.init(doc: "PhysicsComponent")
}
func update(time: NSTimeInterval){
print("updated at \(time)")
}
func move(vector: CGVector) {
print("updated \(vector)")
}
}
// Entity
class Entity {
let events = EventManager()
}
class someClass: Entity {
// components
let inputComponent: Input
let moveComponent: Movement
let physicsComponent: Physics
override init() {
inputComponent = Input()
moveComponent = Movement()
physicsComponent = Physics()
super.init()
inputComponent.events = events
events.add(.input, listener: moveComponent, action: Movement.move)
events.add(.input, listener: physicsComponent, action: Physics.move)
}
}
let someInstance = someClass()
someInstance.inputComponent.goRight()
//moved CGVector(dx: 10.0, dy: 0.0)
//updated CGVector(dx: 10.0, dy: 0.0)
someInstance.events.remove(.input, listener: someInstance.moveComponent, action: Movement.move)
someInstance.inputComponent.goUp()
//updated CGVector(dx: 0.0, dy: -5.0)
someInstance.events.remove(.input, listener: someInstance.physicsComponent, action: Physics.move)
someInstance.inputComponent.goRight()
// nothing
A different approach to how to store a collection of different type signatures. Instead of using generics, casting, or type erasure, use an enum with associated types representing each type of signature you want to use eg
enum Signature{
case cgvector(CGVector -> Void)
case nstimeinterval(NSTimeInterval -> Void)
The disadvantage is that the enum captures a strong reference to the method. However (I need to take this out of a playground to test it more), this doesn't seem to create a strong reference cycle. You can set the containing entity to nil and all of its components appear to be deinitialized. I'm not quite sure what's happening there. To me this enum approach seems cleaner than putting a generic wrapper in an array of AnyObject and have to cast and type-erase constantly.
Comments and criticisms welcome.
/*:
## Entity - Component framework with a notification system for decoupled communications between components
### Limitations:
1. Closure class stores a strong reference to the components. But, a strong reference cycle is not created.
2. A given class instance (component) can only subscribe to a given event with one method.
*/
import Cocoa
import Foundation
enum EventName: String {
case onInput
}
//A type-safe wrapper that stores closures of varying signatures, and allows them to be identified by the hashValue of its owner.
class Closure {
enum Signature {
case cgvector(CGVector -> Void)
case nstimeinterval(NSTimeInterval -> Void)
func invoke(argument: Any){
switch self {
case let .cgvector(closure): closure(argument as! CGVector)
case let .nstimeinterval(closure): closure(argument as! NSTimeInterval)
}
}
}
var method: Signature
weak var owner: Component?
init(owner: Component, action: Closure.Signature) {
method = action
self.owner = owner
}
}
// Entity
class Entity {
var components = Set<Component>()
private var events = [EventName: [Closure]]()
deinit {
print("Entity deinit")
}
// MARK: component methods
func add(component: Component){
components.insert(component)
component.parent = self
}
func remove(component: Component){
unsubscribeFromAll(component)
components.remove(component)
}
func remove<T: Component>(type: T.Type){
guard let component = retrieve(type) else {return}
remove(component)
}
func retrieve<T: Component>(type: T.Type) -> T? {
for item in components {
if item is T { return item as? T}
}
return nil
}
// MARK: event methods
func subscribe(listener: Component, method: Closure.Signature, to event: EventName ){
let closure = Closure(owner: listener, action: method)
// if event array does not yet exist, create it with the closure.
if events[event] == nil {
events[event] = [closure]
return
}
// check to make sure this listener has not subscribed to this event already
if ((events[event]!.contains({ $0.owner! == listener })) == false) {
events[event]!.append(closure)
}
}
func dispatch(argument: Any, to event: EventName ) {
events[event]?.forEach(){ $0.method.invoke(argument) }
}
func unsubscribe(listener: Component, from name: EventName){
//events[name]? = events[name]!.filter(){ $0.hashValue != listener.hashValue }
if let index = events[name]?.indexOf({ $0.owner! == listener }) {
events[name]!.removeAtIndex(index)
}
}
func unsubscribeFromAll(listener: Component){
for (event, _) in events {
unsubscribe(listener, from: event)
}
}
}
//Components
class Component: Hashable {
weak var parent: Entity?
var doc: String { return "Component" }
var hashValue: Int { return unsafeAddressOf(self).hashValue }
deinit {
print("deinit \(doc)")
}
}
func == <T: Component>(lhs: T, rhs: T) -> Bool {
return lhs.hashValue == rhs.hashValue
}
//: #### Usage test
class Input: Component {
override var doc: String { return "Input" }
func goRight() {
parent?.dispatch(CGVector(dx: 10, dy: 0), to: .onInput )
}
func goUp() {
parent?.dispatch(CGVector(dx: 0, dy: -10), to: .onInput )
}
}
class Movement: Component {
override var doc: String { return "Movement" }
func move(vector: CGVector) {
print("moved \(vector)")
}
}
class Physics: Component {
override var doc: String { return "Physics" }
func update(time: NSTimeInterval){
print("updated at \(time)")
}
func move(vector: CGVector) {
print("updated \(vector)")
}
}
// an example factory
var entity: Entity? = Entity()
if let instance = entity {
// a couple of ways of adding components
var inputComponent = Input()
instance.add(inputComponent)
instance.add(Movement())
instance.add(Physics())
var m = instance.retrieve(Movement.self)
instance.subscribe(m!, method: .cgvector(m!.move), to: .onInput)
let p = instance.retrieve(Physics.self)!
instance.subscribe(p, method: .cgvector(p.move), to: .onInput)
inputComponent.goRight()
inputComponent.goUp()
instance.retrieve(Input.self)?.goRight()
instance.remove(Movement.self)
m = nil
inputComponent.goRight()
}
entity = nil //not a strong ref cycle
I fell into that situation but i found a cool solution
with an anonymous inline function, it is like mapping
here is an example
var cellConfigurator: ((UITableViewCell, _ index: IndexPath) -> Void)?
func setup<CellType: UITableViewCell>(cellConfig: ((CellType, _ index: IndexPath) -> ())?)
{
// this mini function maps the closure
cellConfigurator = { (cell: UITableViewCell, _ index: IndexPath) in
if let cellConfig = cellConfig, let cell = cell as? CellType {
cellConfig(cell, index)
}
else
{ print("-- error: couldn't cast cell") }
}
}
I have an array of CGPoints in Swift.
I'd like to find a point in the array using only the X value (they all have unique X values, so this shouldn't be a problem) and then get the Y value from that.
I also would like a way to only see if it contains a point with the X value that I'm looking for, like a .contains that only cares about the X.
You can use the indexOf: function to find the index of an item in an array using a predicate. From there, you can access that item with the index.
This actually answers both your questions, because it either returns the index of a CGPoint with your X-value, or it returns nil.
let index = pointArray.indexOf {
$0.x == xToFind
}
if let index = index {
let point = pointArray[index]
// Do something with the point that has the x-value you wanted
} else {
// There is no point in the array with the x-value you wanted
}
One overly complicated but sweet way to handle problems like this is with Protocols and Extensions.
If we make a XYType protocol that has a typealias Element and x and y properties of type Element we can extend SequenceType to encapsulate the filter and contains methods.
protocol XYType {
typealias Element
var x : Element { get set }
var y : Element { get set }
}
extension CGPoint : XYType {}
Now the real methods :
Extend SequenceType but use constraints. The Generator.Element should be an XYType and the Generator.Element.Element (the Element of the XYType) should be Equatable.
The actual filter function is a bit complicated. But essentially it uses the function it gets as a parameter includeElement: (Self.Generator.Element.Element) throws -> Bool and if it is true it appends to a copy. In the end it returns that copy.
extension SequenceType where Generator.Element : XYType, Generator.Element.Element : Equatable {
// this function just mimics the regular filter.
func filterByX(#noescape includeElement: (Self.Generator.Element.Element) throws -> Bool) rethrows -> [Self.Generator.Element] {
var copy : [Generator.Element] = []
for element in self where try includeElement(element.x) {
do {
let include = try includeElement(element.x)
if include {
copy.append(element)
}
} catch {
continue
}
}
return copy
}
func filterByY(#noescape includeElement: (Self.Generator.Element.Element) throws -> Bool) rethrows -> [Self.Generator.Element] {
var copy : [Generator.Element] = []
for element in self where try includeElement(element.y) {
do {
let include = try includeElement(element.y)
if include {
copy.append(element)
}
} catch {
continue
}
}
return copy
}
}
Do the same for contains
extension SequenceType where Generator.Element : XYType, Generator.Element.Element : Equatable {
func containsX(#noescape predicate: (Self.Generator.Element.Element) throws -> Bool) rethrows -> Bool {
for element in self {
do {
let result = try predicate(element.x)
if result {
return true
}
} catch {
continue
}
}
return false
}
func containsY(#noescape predicate: (Self.Generator.Element.Element) throws -> Bool) rethrows -> Bool {
for element in self {
do {
let result = try predicate(element.y)
if result {
return true
}
} catch {
continue
}
}
return false
}
}
Tests :
let points = [CGPoint(x: 1, y: 1),CGPoint(x: 2, y: 2),CGPoint(x: 3, y: 3),CGPoint(x: 4, y: 4)]
// CGPoint(2,2)
points.filterByY { (y) -> Bool in
y == 2
}
// false
points.containsX { (x) -> Bool in
x == 5
}
P.S. :
you can also do this, it is a little bit shorter :
let filtered = points.filter {
$0.x == 2
}
let contains = points.contains {
$0.x == 3
}