Make Class iterable with a for in Loop? - ios

I have a custom class:
class MyArrayClass {
...
}
This class is a custom list implementation.
I want to do the following:
var arr:MyArrayClass = MyArrayClass()
arr.append("first")
arr.append("second")
arr.append("third")
for entry in arr {
println("entry: \(entry)")
}
Edit: The class I want to make iterable is JavaUtilArrayList it uses this class IOSObjectArray.
Which protocol must be confirmed by my class such that it works in a for in loop?

You should have a look at this blog post on this exact topic. I'll write a summary of it here though:
When you write:
// mySequence is a type that conforms to the SequenceType protocol.
for x in mySequence {
// iterations here
}
Swift converts this to:
var __g: Generator = mySequence.generate()
while let x = __g.next() {
// iterations here
}
Therefore, to be able to enumerate through your custom type you need to make your class implement the SequenceType protocol too. Looking at the SequenceType protocol below, you can see you only need to implement one method that returns an object that conform to the GeneratorType protocol (GeneratorType is covered in the blog post).
protocol SequenceType : _Sequence_Type {
typealias Generator : GeneratorType
func generate() -> Generator
}
Here's an example of how to make MyArrayClass useable in a for loop:
class MyArrayClass {
var array: [String] = []
func append(str: String) {
array.append(str)
}
}
extension MyArrayClass : SequenceType {
// IndexingGenerator conforms to the GeneratorType protocol.
func generate() -> IndexingGenerator<Array<String>> {
// Because Array already conforms to SequenceType,
// you can just return the Generator created by your array.
return array.generate()
}
}
Now to use this in practise:
let arr = MyArrayClass()
arr.append("first")
arr.append("second")
arr.append("third")
for x in arr {
println(x)
}
// Prints:
// First
// Second
// Third
I hope that answers your question.

You can make it much faster using NSFastGenerator:
extension MyArrayClass: SequenceType {
public func generate() -> NSFastGenerator {
return NSFastGenerator(self)
}
}

Related

Generic class type doesn't conform to Any

I have a problem with storing my generic classes in an array. How should I format the type for my array while keeping the reference to the original type (I know I could do var myClasses: [Any] = [] but that wouldn't be helpful when retrieving the variable from my array :(
Example is below:
import UIKit
protocol Reusable { }
extension UITableViewCell: Reusable { }
extension UICollectionViewCell: Reusable { }
class SomeClass<T> where T: Reusable {
init() { }
}
var myClasses: [SomeClass<Reusable>] = []
myClasses.append(SomeClass<UITableViewCell>())
myClasses.append(SomeClass<UICollectionViewCell>())
myClasses.append(SomeClass<UITableViewCell>())
myClasses.append(SomeClass<UICollectionViewCell>())
Edit: Just to clarify, I have used the collection and table cells as an example, I am not actually planning on storing them together :)
Edit 2 var myClasses: [SomeClass<Reusable>] = [] generates error: using 'Reusable' as a concrete type conforming to protocol 'Reusable' is not supported
Edit 3 var myClasses: [SomeClass<AnyObject>] = [] generates error: type 'AnyObject' does not conform to protocol 'Reusable'
I think you can create some sort of Holder class that can accept and retrieve your object:
class Holder {
lazy var classes: [Any] = []
func get<T>(_ type: T.Type) -> [T]? {
return classes.filter({ $0 is T }) as? [T]
}
}
And the main part:
let holder = Holder()
holder.classes.append(SomeClass<UITableViewCell>())
if let someTableViewCells = holder.get(SomeClass<UITableViewCell>.self)?.first {
// or filter out again to get specific SomeClass of UITableViewCell
print(someTableViewCells)
}
Or without holder class:
var classes: [Any] = []
classes.append(SomeClass<UITableViewCell>())
if let someTableViewCell = classes.filter({ $0 is SomeClass<UITableViewCell> }).first as? SomeClass<UITableViewCell> {
print(someTableViewCell)
}
You should use array of AnyObject in your case. Because as you know swift is strong typed language and for example
SomeClass<UITableViewCell>
and
SomeClass<UICollectionViewCell>
are different types of objects. As for example Array< Int > and Array< String >, they are both arrays, but still it's a different types of objects. So in this case you'll have to use declaration:
var myClasses: [AnyObject] = []
and check type of object or typecast them every time you'll need.
if (myClasses[0] is SomeClass<UICollectionViewCell>) { do something }
or
if let cell = myClasses[0] as? SomeClass<UICollectionViewCell> { do something }
My suggestion is adding parent protocol SomeClass Container for your SomeClass generic. Then put an array of SomeClass objects inside SomeClass.
protocol Reusable { func cakePlease() }
extension UITableViewCell: Reusable {
func cakePlease() { }
}
extension UICollectionViewCell: Reusable {
func cakePlease() { }
}
protocol SomeClassContainer {
func teaPlease()
func afternoonPlease()
}
class SomeClass<T: Reusable>: SomeClassContainer {
var item: T?
init() { }
func teaPlease() { }
func afternoonPlease() {
teaPlease()
item?.cakePlease()
}
}
var myClasses = [SomeClassContainer]()
myClasses.append(SomeClass<UITableViewCell>())
myClasses.append(SomeClass<UICollectionViewCell>())
myClasses.append(SomeClass<UITableViewCell>())
myClasses.append(SomeClass<UICollectionViewCell>())
myClasses[0].teaPlease()
if let item = (myClasses[0] as? SomeClass<UITableViewCell>)?.item {
item.cakePlease()
}
for myClass in myClasses {
if let tableCell = (myClass as? SomeClass<UITableViewCell>)?.item {
tableCell.cakePlease()
} else if let collectionCell = (myClass as SomeClass<UICollectionViewCell>)?.item {
collectionCell.cakePlease()
}
}
myClasses.forEach({ $0.afternoonPlease() })
Generally the way to type your array would be to go as specific as possible whilst still covering all bases.
What I mean by this for example is storing an array of UIViewController objects, even though each will actually be a different type. You wouldn't use Any here because you really don't need to be that general.
In your case, why not use Reusable? Since all your generic classes conform to it anyway, it is as general as you can go whilst still maintaining convenience.

Enforce template to be a protocol

How do I ensure that a given template parameter is a protocol?
A GKEntity has a function called component(ofType: class) and i want to add component(ofProtocol: Protocol). It does look like this:
extension GKEntity {
func component<T: Protocol>(ofProtocol: T) -> T? {
return self.components.first() { component in
return component.conforms(to: ofProtocol)
} as? T
}
}
I want to use it in an component which holds a reference to the entity like this:
let component = self.entity?.component(ofProtocol: SpriteComponentProtocol)
but somehow i always get:
Showing All Messages
Cannot convert value of type 'SpriteComponentProtocol.Protocol' to expected argument type 'Protocol'
Update:
The idea is that i have a component for a Sprite:
protocol SpriteComponentProtocol {
var spriteNode: SKSpriteNode { get set }
}
class SpriteComponent: GKComponent {
var spriteNode: SKSpriteNode?
}
And a other component for the control:
protocol PlayerControlComponentProtocol {
var steerAngle: Double { get set }
}
class PlayerControlComponent: GKComponent, PlayerControlComponentProtocol {
var steerAngle: Double = 90.0
override func update(deltaTime seconds: TimeInterval) {
//here i do manipulate the spriteComponent.spriteNode
let comp = self.entity?.component(ofProtocol: SpriteComponentProtocol)
}
}
I want to be able to exchange the SpriteComponent at any time.
The problem with your code is that Protocol is an opaque type that describes an Obj-C protocol, so if you want to bridge SpriteComponentProtocol.self over to it, you need to mark SpriteComponentProtocol as #objc (but even if you did; you wouldn't be able to cast to T, because the returned instance isn't of type Protocol).
But that being said, you don't need to use the Obj-C Protocol type or conforms(to:) method here, you can simply use the conditional type-casting operator as? in an overload of component(ofType:) without the GKComponent constraint on T:
extension GKEntity {
func component<T>(ofType type: T.Type) -> T? {
return self.components.lazy.flatMap{ $0 as? T }.first
}
}
We're using lazy here in order to avoid evaluating all the components, and then flatMap(_:) and first in order to get the first element that's castable to T (and in the case of T being a protocol type, this gives us the first element that conforms to the protocol).
You can then simply use it like so:
protocol SpriteComponentProtocol {
var spriteNode: SKSpriteNode { get set }
}
class PlayerControlComponent: GKComponent {
override func update(deltaTime seconds: TimeInterval) {
let comp = self.entity?.component(ofType: SpriteComponentProtocol.self)
}
}
And in Swift 4, you can remove this overload entirely, and instead simply call GKEntity's component(ofType:) method with a class existential metatype:
let comp = self.entity?.component(ofType: (GKComponent & SpriteComponentProtocol).self)
As now T satisfies the : GKComponent constraint. You can then access both GKComponent methods and SpriteComponentProtocol protocol requirements on the unwrapped instance.

How to implement a computed property like a abstract property in Swift?

I know there is no abstract class and either Abstract keyword in Swift. The following problem just like implementing a abstract property.
For convenient, supposed that there are three classes as following:
class SuperClass: NSManagedObject { // the compiler will complain without 'NSManagedObject', and I don't know why.
public let superInt: Int = 1 // use superInt to represent other stored property for SuperClass.
}
class SubClass1: SuperClass {
let subInt1: Int = 2 // use 'subInt1' to represent other stored property for SubClass1.
}
class SubClass2: SuperClass {
let subInt2: Int = 3 // use 'subInt2' to represent other stored property for SubClass2.
}
protocol TestProtocol {
var count: Int { get } // a computed property
func printInt() // a custom method
}
Here, those classes are all objects defined in CoreData, especially SuperClass is a abstract Entity. I want to extend some interfaces(the TestProtocol above) for SuperClass, so that I can use polymorphism. I come up with 2 methods:
Method 1: let SuperClass confirms TestProtocol.
extension SuperClass: TestProtocol {
var count: Int { return superInt }
func printInt() { print("Here is SuperClass. Count: \(count)") }
}
extension SubClass1 {
override var count: Int { return subInt1 }
override func printInt() { print("Here is SubClass1. Count is \(count)") }
}
extension SubClass2 {
override var count: Int { return subInt2 }
override func printInt() { print("Here is SubClass2. Count is \(count)") }
}
// Here is the test code
let subClasses: [SuperClass] = [SubClass1(), SubClass2()]
subClasses.forEach { $0.printInt() }
Method 2: Convert subClasses to a protocol object.
extension SubClass1: TestProtocol {
var count: Int { return subInt1 }
func printInt() { print("Here is SubClass1. Count is \(count)") }
}
extension SubClass2: TestProtocol {
var count: Int { return subInt2 }
func printInt() { print("Here is SubClass1. Count is \(count)") }
}
// Here is the test code
let subClasses: [SuperClass] = [SubClass1(), SubClass2()]
subClasses.forEach { ($0 as! TestProtocol).printInt() }
In method 1, everything looks good. But I have to implement the code in SuperClass which is totally useless. The method seems like a little trick of grammar.
In method 2, all code is useful, but the conversion at last line broke the elegance of code. It makes me crazy continuously using code like ($0 as! TestProtocol).printInt().
I'm not satisfied with both methods. So which is recommended way or is there a better way to do it?
In your second method you actually do not need to use casting (($0 as! TestProtocol).printInt()). Here is how:
let subClasses: [TestProtocol] = [SubClass1(), SubClass2()]
subClasses.forEach { $0.printInt() }
By typing the subClasses array to TestProtocol instead of SuperClass you can remove the need for casting because the compiler now knows that every element in subClasses conforms to TestProtocol and thus, has a method printInt().
Your super class does not serve any purpose in both method 1 and method 2. In both methods you have defined, you want to eventually call printInt() which should be common to all sub classes. Notice I have highlighted "should be common". The purpose of a protocol is to specify requirements that conforming types must implement. Therefore, a protocol is sufficient to form the contract that your classes 1 and 2 should implement var count and func printInt(). Also a protocol is a type, so you do not need a super class to hold references to the other two classes as you did here:
let subClasses: [SuperClass] = [SubClass1(), SubClass2()]
In my opinion, this would be a better way:
protocol TestProtocol {
var count: Int { get } // a computed property
func printInt() // a custom method
}
Class1: TestProtocol {
var subInt = 2
var count: Int { return subInt1 }
func printInt() { print("Here is SubClass1. Count is \(count)") }
}
Class2: TestProtocol {
var subInt = 3
var count: Int { return subInt2 }
func printInt() { print("Here is SubClass2. Count is \(count)") }
}
let smallClasses: [TestProtocol] = [Class1(), Class2()]
smallClasses.forEach { $0.printInt() }
This way of doing things fulfills the Protocol Oriented way of programming in Swift, which is the favored approach. Generally speaking, inheritance and subclassing is shunned in iOS design patterns and I will direct you to this blog post so you can learn more about why https://krakendev.io/blog/subclassing-can-suck-and-heres-why
EDIT
You have clarified your question a bit more so I am going to attempt to answer it better. You are looking for the equivalent of what is an abstract class in Java which are classes that contain one or more abstract methods. An abstract method in Java is a method that is declared, but contains no implementation. Abstract classes may not be instantiated, and require subclasses to provide implementations for the abstract methods.
Swift does not come with the same functionality but something that is functionaly equivalent would require a super class where all sub classes are forced to implement properties or methods that must be common to all sub classes. This is of course achieved by the protocol method I have shown above but you also require the ability to call properties or methods from the super class from the sub class which means each sub class must be able to cast as both the protocol type and the super class type.
Here is my solution to that written in Swift 3:
protocol TestProtocol {
var count: Int { get } // a computed property
func printInt() // a custom method
}
//base class
class SuperClass: TestProtocol {
var sharedInt: Int = 0
var subInt: Int = 1
var count: Int { return subInt }
func printInt() { print("Here is SubClass. Count is \(count)") }
}
class class1: SuperClass {
override init(){
super.init()
self.subInt = 2
}
}
class class2: SuperClass {
override init(){
super.init()
self.subInt = 3
}
}
//I can get count and printInt() which superClass, class1 and class2 share becuase of the protocol.
let smallClasses: [TestProtocol] = [SuperClass(), class1(), class2()]
smallClasses.forEach { $0.printInt() }
//I can convert the sub classes to super class type and call their printInt method
let smallClasses2: [SuperClass] = [class1(), class2()]
smallClasses2.forEach { $0.printInt() }
//I can get to the shared values the sub classes have from the super class
smallClasses2.forEach { print($0.sharedInt) }
If you copy and paste the code above into a Playground in Xcode, you will receive the following output:
Here is SubClass. Count is 1
Here is SubClass. Count is 2
Here is SubClass. Count is 3
Here is SubClass. Count is 2
Here is SubClass. Count is 3
0
0

Swift generic class which could take Array of elements or single element

I would like to make generic class which will be able to take Parsable type, or Array of Parsable type. Logic for both are almost the same so i don't want to make two different class for this operation. Is it possible to solve it using Swift generics, or protocol associatedtype types?
protocol Parsable: class {
associatedtype Type
static func objectFromDictionary(dictionary: Dictionary<String, AnyObject>, inContext context: NSManagedObjectContext) -> Type?
func importFromDictionary(dictionary: Dictionary<String, AnyObject>)
}
class ParseOperation<T: Parsable>: NSOperation {
func execute() -> T {
}
}
class ParseOperation<T where T: SequenceType, T.Generator.Element == Parsable>: NSOperation {
func execute() -> T {
// Do parsing
}
}
This i how i would like to work:
class ParseOperation<T where T: SequenceType, T.Generator.Element == Parsable OR T: Parsable>: NSOperation {
func execute() -> T {
// Do parsing
}
}
In my current implementation i am using enum which looks little bit ugly:
class ParseOperation<T where T: NSManagedObject, T:Parsable>: NSOperation {
var responseToParse: AnyObject?
var parseType: ParseType
var parsedObjects: [T]?
init(parseType: ParseType) {}
func execute() {
var objects: [NSManagedObject] = []
if self.parseType == .Single {
if let responseToParse = self.responseToParse as? Dictionary<String, AnyObject>,
let parsedObject = T.objectFromDictionary(responseToParse, inContext: localContext) {
objects.append(parsedObject)
}
} else if self.parseType == .Array {
if let responseToParse = self.responseToParse as? Array<Dictionary<String, AnyObject>> {
for dictionary in responseToParse {
if let parsedObject = T.objectFromDictionary(dictionary, inContext: localContext) {
objects.append(parsedObject)
}
}
}
}
self.parsedObjects = objects
...
}
}
I modified #RonaldMartin 's answer to show how ParsableArray might help you. It don't need to take input of Parsable elements, just implement parse function this way:
protocol Parsable {
associatedtype T
static func parse(input: AnyObject) -> T?
}
struct ParsableArray<TElement where TElement: Parsable>: Parsable {
static func parse(input: AnyObject) -> [TElement.T]? {
guard let arrayInput = input as? [AnyObject] else {
return nil
}
return arrayInput.flatMap(TElement.parse)
}
}
I've renamed objectFromDictionary to parse because it's need to take AnyObject not the Dictionary to be able to parse array. You can add context or whatever you like to parse method, of course.
If Parsable done this way then ParseOperation becomes very simple:
class ParseOperation<T where T: Parsable>: NSOperation {
let input: AnyObject
var result: T.T?
init(input: AnyObject) {
self.input = input
}
override func main() {
result = T.parse(input)
}
}
Then, you can parse arrays this way (note: this is only to demonstrate how to create ParseOperation; S is just some Parsable struct):
let op = ParseOperation<ParsableArray<S>>(input: [["1": 5, "2": 6], ["3": 10]])
op.main()
var r: [S]? = op.result
I hope, this will help.
As far as I know, the type constraint system is not designed to handle OR constraints. However, it should still be possible to do what you're asking.
One approach is to represent both singleton Parsables and collections of Parsables under a single type that you can use to constrain ParseOperation. The neatest way to do this would be to extend Array (or SequenceType, CollectionType, etc.) to conform to the Parsable type as well, but this is not yet possible as of Xcode 7.3. You can use the same workaround from that linked question and add an intermediate class to represent Parsable arrays:
class ParsableArray: Parsable {
let array: [Parsable]
init(array: [Parsable]) {
self.array = array
}
// Parsable conformance...
}
Now, you can just use the original protocol for your type constraint:
class ParseOperation<T: Parsable>: NSOperation {
func execute() -> T {
// Do parsing
}
}
Ideally you should be able to do this:
// This DOES NOT compile as of XCode 7.3
extension Array: Parsable where Element: Parsable {
// Parsable implementation
}
However it currently doesn't work.
Currently you have to rely on a wrapper struct:
struct ParsableArray<Element: Parsable>: Parsable {
let array: [Element]
init(_ array: [Element]) {
self.array = array
}
// Parsable implementation
}
You can also implement a convenience method for [Parsable] arrays:
extension Array where Element: Parsable {
func toParsable() -> ParsableArray<Element> {
return ParsableArray(self)
}
}
So you could execute your method like this:
let array = [Parsable]()
parse(array.toParsable()) // Equivalent to: parse(ParsableArray(array))

Making a Swift Array conform to a Protocol

Let's say that certain items can appear in a Feed, so long as they implement the necessary properties defined by the Feedable protocol. Let's also say that the Photo object is feed-worthy:
extension Photo: Feedable { }
Is it possible to say that an Array of these photos might also be Feedable?
extension [Photo] : Feedable
Or do I always need some kind of wrapper object, such as a PhotoAlbum, to conform to Feedable?
Edit
To re-iterate, I was curious whether I can make only arrays of Photo objects Feedable. Not making Array of any content type Feedable, not making an array of Feedables itself Feedable (both of which are offered as solutions below if that's what you need).
In other words, a solution (which I doubt exists) would allow me to define a variable of type Feedable with the following outcomes:
var feedable: Feedable
//photo is feedable, so this is fine
feedable = Photo() //ok
//arrays of photos are feedable
let photo1 = Photo()
let photo2 = Photo()
feedable = [photo1, photo2]
//arrays of other things are not
feedable = ["no", "dice"] //nope
//even if the contents of an array are themselves Feedable, that's not sufficient. E.g. Video is Feedable, but Array of Videos is not.
let video1 = Video()
let video2 = Video()
feeble = video1 //fine
feedable = [video1, video2] //nope
Perhaps this gist (which doesn't compile of course) shows the intention more clearly.
You can achieve your goal in this way:
Swift 4:
protocol Feedable {
func foo()
}
extension String: Feedable {
func foo() {
}
}
extension Array: Feedable where Element: Feedable {
func foo() {
}
}
// or in more generic way to support Array, Set and other collection types
extension Collection: Feedable where Element: Feedable {
func foo() {
}
}
If there was an array of Photo and Video,what would you like to be?
1.Every element performs like what they are.
extension Array where Element : Feedable {
func foo() {
if Element.self == Photo.self {
} else {
}
}
}
2.The whole array performs as 'Video'.
extension Array where Element : Photo {
func foo() {
}
}
I think this is currently not possible. In my project I have the same issue with a ModelProducer.
protocol M: ModelType {}
protocol ModelProducerType {
associatedtype M: ModelType
var model: M? { get }
func produce()
}
struct Test: ModelType {}
class TestProducer: ModelProducerType {
var model: Test?
func produce() {
model = Test()
}
}
I use ModelType as a ghost protocol. The problem is I cannot make a model producer that produces multiple ModelTypes, because of the same reason you discovered. The solution in this case was the following:
protocol M: ModelType {}
protocol ModelProducerType {
associatedtype M: ModelType
var model: [M] { get }
func produce()
}
struct Test: ModelType {}
class TestProducer: ModelProducerType {
var model: [Test] = []
func produce() {
model = [Test()]
}
}
This is more flexible from the start. I get rid of the optional variable and single model producers just have one item in the array. Maybe you can use a similar approach.
You can make an array to conform a protocol like this:
typealias PhotoArray = [Photo]
extension PhotoArray: Feedable {}
I didn't try in playground but maybe you can simply make an Array of Feedable:
var myPhotosArray = [Feedable]()
Then everything implementing the Feedable protocol would be allowed in the Array. If you want only a photo array, You can still subclass your Photo object to make a FeedablePhoto object.
Try this in Playground instead of downvoting without even testing.
Seriously 3 downvotes without any reasons and explanations...
import UIKit
protocol Tree: class {
func grow()
}
class BigTree: Tree {
internal func grow() {
print("Big tree growing")
}
}
class SmallTree: Tree {
internal func grow() {
print("Small tree growing")
}
}
class Car {
//not a tree
}
var manyTrees = [Tree]()
manyTrees.append(BigTree())
manyTrees.append(SmallTree())
manyTrees.append(Car()) //This makes an error "Car doesn't conform to expected type 'Tree'"

Resources