Extending CollectionType with optional initialiser - ios

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.

Related

How Accss JsonData from given image

array product modeldetail models
My code:
productDetailsNameLabel.text = products[indexPath.section].arr_details?[indexPath.item].productname
Getting error message:
Type Arr_Details has no subscripts member
arr_details not have any subscript members so you cannot access it. Please refer following example:
class Abc: NSObject {
var arr: [Xyz] = []
override init() {
for i in 1...5 {
arr.append(Xyz(number: i))
}
}
}
class Xyz: NSObject {
var number: Int
init(number: Int) {
self.number = number
}
}
// Use of this class
var arrAbc: [Abc] = []
for _ in 0...5 {
arrAbc.append(Abc())
}
yourLabel.text = "\(arrAbc[0].arr[0].number)"
arr_details doesn't have a subscript so that it doesn't return a value.
In order to use the subscript, you have to implement it on the arr_detail type.

Heterogeneous mixture of protocol types, including a generic protocol

protocol ParentProtocol { }
protocol ChildProtocol: ParentProtocol { }
protocol Child_With_Value_Protocol: ParentProtocol {
associatedType Value
func retrieveValue() -> Value
}
Attempting to create a single array of type ParentProtocol that contains both ChildProtocol and Child_With_Value_Protocol. Is there any possible way to create a function that loops through the heterogeneous array and returns the values of just type Child_With_Value_Protocol?
This may require an architecture change. Open to all solutions.
Attempted Failed Solution #1
var parents: [ParentProtocol] = [...both ChildProtocol & Child_With_Value_Protocol...]
func retrieveValues() -> [Any] {
var values = [Any]()
for parent in parents {
if let childWithValue = parent as? Child_With_Value_Protocol { // Fails to compile
values.append(childWithValue.retrieveValue())
}
}
return values
}
This fails with an error of protocol 'Child_With_Value_Protocol' can only be used as a generic constraint because it has Self or associated type requirements which makes sense since the compiler would not know the type when converted to just Child_With_Value_Protocol, this leads to the next failed solution.
Attempted Failed Solution #2
If the array was a homogeneous array of just Child_With_Value_Protocol, type erasing could be used to retrieve the values.
var parents: [ParentProtocol] = [...both ChildProtocol & Child_With_Value_Protocol...]
struct AnyValue {
init<T: Child_With_Value_Protocol>(_ protocol: T) {
_retrieveValue = protocol.retrieveValue as () -> Any
}
func retrieveValue() -> Any { return _retrieveValue() }
let _retrieveValue: () -> Any
}
func retrieveValues() -> [Any] {
var values = [Any]()
for parent in parents {
values.append(AnyValue(parent).retrieveValue()) // Fails to compile
}
return values
}
This fails to compile due to the fact that the struct AnyValue has no initializer for the ParentProtocol.
Attempted Failed Solution #3
struct AnyValue {
init<T: Child_With_Value_Protocol>(_ protocol: T) {
_retrieveValue = protocol.retrieveValue as () -> Any
}
func retrieveValue() -> Any { return _retrieveValue() }
let _retrieveValue: () -> Any
}
var erased: [AnyValue] = [AnyValue(...), AnyValue(...), AnyValue(...)]
func retrieveValues() -> [Any] {
var values = [Any]()
for value in erased {
values.append(value.retrieveValue())
}
return values
}
Unlike the other solutions, this solution actually compiles. Problem with this solution resides in the fact that the array erased can only hold values of the type-erased versions of Child_With_Value_Protocol. The goal is for the array to hold types of both Child_With_Value_Protocol and ChildProtocol.
Attempted Failed Solution #4
Modifying the type-erase struct to include an initializer for ParentProtocol still creates a solution that compiles, but then the struct will only use the less specific init, instead of the more specific init.
struct AnyValue {
init?<T: ParentProtocol>(_ protocol: T) {
return nil
}
init?<T: Child_With_Value_Protocol>(_ protocol: T) {
_retrieveValue = protocol.retrieveValue as () -> Any
}
func retrieveValue() -> Any { return _retrieveValue() }
let _retrieveValue: (() -> Any)?
}
The prior comments are likely right. Nevertheless, you could box the variants in an enum and create an array of those. The reference would then switch on the enum value, each having associated data of the right type
EDIT: I didn't bother with the associatedValue, because it seems irrelevant to the question being asked. The following works in a playground:
protocol ParentProtocol: CustomStringConvertible {
static func retrieveValues(parents: [FamilyBox]) -> [ParentProtocol]
}
protocol ChildProtocol: ParentProtocol { }
protocol Other_Child_Protocol: ParentProtocol { }
enum FamilyBox {
case Parent(parent: ParentProtocol)
case Child(child: ChildProtocol)
case OtherChildProtocol(withValue: Other_Child_Protocol)
}
var parents: [FamilyBox] = []
struct P: ParentProtocol {
var description: String { return "Parent" }
static func retrieveValues(parents: [FamilyBox]) -> [ParentProtocol] {
var values = [ParentProtocol]()
for parent in parents {
switch parent {
case .Parent(let elementValue):
values.append(elementValue)
default:
break;
}
}
return values
}
}
struct C: ChildProtocol {
var description: String { return "Child" }
static func retrieveValues(parents: [FamilyBox]) -> [ParentProtocol] {
var values = [ParentProtocol]()
for parent in parents {
switch parent {
case .Child(let elementValue):
values.append(elementValue)
default:
break;
}
}
return values
}
}
struct CV: Other_Child_Protocol {
var description: String { return "Other Child" }
static func retrieveValues(parents: [FamilyBox]) -> [ParentProtocol] {
var values = [ParentProtocol]()
for parent in parents {
switch parent {
case .OtherChildProtocol(let elementValue):
values.append(elementValue)
default:
break;
}
}
return values
}
}
let p = FamilyBox.Parent(parent: P())
let c = FamilyBox.Child(child: C())
let cv = FamilyBox.OtherChildProtocol(withValue: CV())
let array:[FamilyBox] = [p, c, cv]
print(P.retrieveValues(array))
print(C.retrieveValues(array))
print(CV.retrieveValues(array))
The prints from the last three lines are:
[Parent]
[Child]
[Other Child]
While I'm sure it can be improved, I think that meets the original intent. No?

Generic constraint for any protocol in Swift

Is it possible to constrain generic type to accept protocol in Swift?
I have implemented wrapper to have weak list of objects, and I need to extend that to protocols.
protocol Incrementable: class {
func inc()
}
class Counter: Incrementable {
var n: Int = 0
func inc() {
n += 1
}
}
struct Weak<T: AnyObject> {
weak var value : T?
init (value: T?)
{
self.value = value
}
}
var cnt: Counter? = Counter()
let counters : [Weak<Counter>] = [Weak(value: cnt), Weak(value: Counter())]
for counter in counters
{
counter.value?.inc()
}
Now if I want to store any object that implements Incrementable I have to use AnyObject and that is not very type safe and also includes as? casting
let counters : [Weak<AnyObject>] = [Weak(value: cnt), Weak(value: Counter())]
for counter in counters
{
(counter.value as? Incrementable)?.inc()
}
And code I would like to have would be
let counters: [Weak<Incrementable>] = [Weak(value: cnt), Weak(value: Counter())]
for counter in counters
{
counter.value?.inc()
}
Of course, above code cannot be compiled and fails with:
Using 'Incrementable' as concrete type conforming to protocol
'AnyObject' is not supported
Is it possible to write Weak wrapper so it can accept and store weak references to protocol?
While root cause of my problem is same as in Using as a concrete type conforming to protocol AnyObject is not supported that question deals with hash tables and I need solution with lists that allows duplicate entries.
Following answer pointed me in right direction and I was able to come up with following solution for implementing weak list of protocol references that allows duplicates and nil (convenience) entries.
struct Weak<T>
{
weak var value: AnyObject?
init (value: T?)
{
if value != nil
{
guard value is AnyObject else { fatalError("Object (\(value)) should be subclass of AnyObject") }
self.value = value as? AnyObject
}
}
}
class WeakList<T>: SequenceType
{
var items : [Weak<T>] = []
func add(item: T?)
{
items.append(Weak(value: item))
}
func generate() -> AnyGenerator<T>
{
var nextIndex = items.count - 1
return anyGenerator
{
while nextIndex >= 0
{
let item = self.items[nextIndex--]
if item.value != nil
{
return item.value as? T
}
}
return nil
}
}
}
let incrementables = WeakList<Incrementable>()
incrementables.add(Counter())
incrementables.add(cnt)
incrementables.add(nil)
incrementables.add(Counter())
incrementables.add(cnt)
for counter in incrementables
{
counter.inc()
}

Swift generic function parameter as Class

I'm not sure that this not duplicate. I have protocol and several classs that confurm to it.
protocol DbObject: class {
class func tableName() -> String
init(set: FMResultSet)
func save(db: FMDatabase)
}
And here how I use it:
func updateTable<T where T:DbObject>(nodes: [T]) {
self.db.executeUpdate("DELETE from \(T.tableName())")
for elem in nodes {
elem.save(self.db)
}
}
func loadAllFromObjectTable<T where T:DbObject>(cl: T) -> [T] {
var objArr = [T]()
if let set = db.executeQuery("select * from \(T.tableName())") {
while (set.next() ?? false) {
let obj = T(set: set)
objArr.append(obj)
}
}
return objArr
}
But I wanna that function loadAllFromObjectTable get as parameter class that confirms protocol, not object. How can I achieve that?
EDIT:
From here https://stackoverflow.com/a/26229630/820795
func loadAllFromObjectTable<T where T:DbObject>(_: T.Type) -> [T] {
var objArr = [T]()
if let set = db.executeQuery("select from \(T.tableName())") {
while (set.next() ?? false) {
if let obj = T(set: set)
objArr.append(obj)
}
}
return objArr
}
And usage:
manager.loadAllFromObjectTable(SignNote.self)

Custom sequence for Swift Dictionary

I have a container class that has an underlying dictionary. I have implemented subscripts for this class to access member of the underlying dictionary. Now, I am trying to create a sequence on this class so that I could iterate over all the elements of the underlying dictionary by using 'for-in' loop on the class instance itself. I have been looking to find some examples for Sequences for Swift Dictionary but could not find anything that explains the stuff well. I have seen some custom sequence examples for Swift Array but none for the Swift Dictionary. I would really appreciate if anyone could explain how I can achieve that. Following is the code for the class (no sequence code yet as I am not sure where to begin)
import Foundation
class STCQuestionList : GeneratorType, SequenceType {
private var questionDict: [String : STCQuestion] = [ : ];
subscript(key : String?) -> STCQuestion? {
get {
if (key != nil) {
return self.questionDict[key!];
}
return nil;
}
set(newValue) {
if (key != nil) {
self.questionDict[key!] = newValue;
}
}
}
func generate() -> GeneratorType {
}
func next() -> (String, STCQuestion)? {
if (self.questionDict.isEmpty) {
return .None
}
}
}
If I'm understanding correctly, how about just forwarding on the generate?
func generate() -> DictionaryGenerator<String, STCQuestion> {
return questionDict.generate()
}
(You don't need to implement GeneratorType, just SequenceType should do. It's generate() itself that returns a GeneratorType, and that's what has to implement next(), which the existing generate() implementation in Dictionary already does for you.)
Full worked example based on your code:
// Playground - noun: a place where people can play
import Foundation
class STCQuestion {
let foo: String
init(_ foo: String) {
self.foo = foo
}
}
class STCQuestionList : SequenceType {
private var questionDict: [String : STCQuestion] = [ : ];
subscript(key : String?) -> STCQuestion? {
get {
if key != nil {
return self.questionDict[key!];
}
return nil;
}
set(newValue) {
if key != nil {
self.questionDict[key!] = newValue;
}
}
}
func generate() -> DictionaryGenerator<String, STCQuestion> {
return questionDict.generate()
}
}
var list = STCQuestionList()
list["test"] = STCQuestion("blah")
list["another"] = STCQuestion("wibble")
list["third"] = STCQuestion("doodah")
for (key, value) in list {
println("Key: \(key) Foo: \(value.foo)")
}
// Output:
// Key: test Foo: blah
// Key: another Foo: wibble
// Key: third Foo: doodah
(Note: I re-thought this -- original answer via the edited page...)
Swift has a generic GeneratorOf type that you can use to create a generator. You just provide a closure that returns the next value in the initializer:
class STCQuestionList : SequenceType {
private var questionDict: [String : STCQuestion] = [ : ];
subscript(key : String?) -> STCQuestion? {
get {
if (key != nil) {
return self.questionDict[key!];
}
return nil;
}
set(newValue) {
if (key != nil) {
self.questionDict[key!] = newValue;
}
}
}
/// Creates a generator for each (key, value)
func generate() -> GeneratorOf<(String, STCQuestion)> {
var index = 0
return GeneratorOf<(String, STCQuestion)> {
if index < self.questionDict.keys.array.count {
let key = self.questionDict.keys.array[index++]
return (key, self.questionDict[key]!)
} else {
return nil
}
}
}
}
If you don't care about the order, can't you just call the same methods of dictionary or make your class a subclass of a dictionary? For example:
func generate() -> GeneratorType {
return self.questionDict.generate()
}
func next() -> (String, STCQuestion)? {
return self.questionDict.next()
}

Resources