Downcast Generic AnyObject to Protocol Associated Type Self.Model - ios

I am developing a library Restofire in which i want to keep a configuration object. I want to have a ResponseSerializer in the configuration object but the thing is ResponseSerializer is a generic.
public struct Configuration<M> {
/// The Default `Configuration`.
static let defaultConfiguration = Configuration<AnyObject>()
/// The base URL. `nil` by default.
public var baseURL: String!
/// The `ResponseSerializer`
public var responseSerializer: ResponseSerializer<M, NSError> = AlamofireUtils.JSONResponseSerializer()
/// The logging, if enabled prints the debug textual representation of the
/// request when the response is recieved. `false` by default.
public var logging: Bool = false
}
I set up the defaultConfiguration with baseUrl Configuration.defaultConfiguration.baseUrl = "http://httpbin.org/"
I have a protocol with associatedType requirement which uses the defaultConfiguration as default implementation. But i require to change the generic AnyObject to the associatedType Model so the responseSerializer of configuration object returns the type Model.
public protocol Configurable {
associatedtype Model
/// The Restofire configuration.
var configuration: Configuration<Model> { get }
}
public extension Configurable {
/// `Restofire.defaultConfiguration`
// Cannot convert return expression of Configuration<AnyObject> to return type Configuration <Self.Model>
public var configuration: Configuration<Model> {
return Restofire.defaultConfiguration
}
}
I get the error Cannot convert return expression of Configuration<AnyObject> to return type Configuration <Self.Model>
How can i downcast to use Model instead of AnyObject ?
I also have a protocol Requestable that inherits from Configurable
public protocol Requestable: Configurable {
/// The type of object returned in response.
associatedtype Model
/// The base URL.
var baseURL: String { get }
/// The path relative to base URL.
var path: String { get }
/// The request parameters.
var parameters: AnyObject? { get }
/// The logging.
var logging: Bool { get }
/// The Response Serializer
var responseSerializer: ResponseSerializer<Model, NSError> { get }
}
// MARK: - Default Implementation
public extension Requestable {
/// `configuration.BaseURL`
public var baseURL: String {
return configuration.baseURL
}
/// `nil`
public var parameters: AnyObject? {
return nil
}
/// `configuration.logging`
public var logging: Bool {
return configuration.logging
}
/// `configuration.responseSerializer`
var responseSerializer: ResponseSerializer<Model, NSError> {
return configuration.responseSerializer
}
}
RealCode at https://github.com/Restofire/Restofire/compare/Add/DefaultResponseSerializer
I could do directly below but then the user will not be able to set it using the configuration object.
// MARK: - Default Implementation
public extension Requestable {
/// `configuration.responseSerializer`
var responseSerializer: ResponseSerializer<Model, NSError> {
return AlamofireUtils.JSONResponseSerializer()
}
}
Is there any other way ?

What you are trying to do is not possible. This is because of the strong type safety system in Swift.
It looks like you want to restrict the configuration to the associated type Model, but you also want to provide a default configuration. The issue here is that your default configuration has no guarantee that its generic type will be the same as the type of Model.
The Swift type system won't let you pass <AnyObject> as type <Model>, as it has no way to ensure that the object actually IS of the Model type.
When you make something conform to Configurable and declare the type of the Model, you are saying, "My configuration must use the type I've given." The defaultConfiguration can't guarantee that, so it cannot be used in this way.
From looking at your code, you are using this to determine the type of the responseSerializer to use. But, if you are using different Configurable objects, they will all need different responseSerializers, so they can't all use the default configuration.
I've spent a lot of time thinking about this problem, and I don't see any way around it. You are going to have to change your design in some way.
If you move the responseSerializer on to the Configurable protocol, then you could make the Configuration non-generic. In that case, you would be able to create the responseSerializer in a protocol extension on Configurable. If you need to use the responseSerializer with a configuration independently of a Configurable object, then you would have to create a responseSerializer<AnyObject, NSError> wherever it is that you are using it. I'm not familiar with the entire design and intent of your library, so I'm not sure if this will work for what you are trying to achieve.
The one thing I can tell you with certainty is that your design has to change in order to use the defaultConfiguration.

Related

Not able to pass value to another class

I want to append a certain "id" to an api. This is the initial portion of how I make the API call in my viewController..
func myAPICall() {
APIHelper(API: WebServices.getAllOrganizations as NSString, json: bodyStr as NSString,
methodType: Constants.Get_Method as NSString....)
}
Now, WebServices.getAllOrganizations is defined elsewhere, in a swift file like so...
public class WebServices {
static let getAllOrganizations: String = "organization/getAllOrganizationDetails
}
MY ATTEMPT TO PASS THE ID TO THE SWIFT FILE :
To pass the value, I assigned it to a global variable like so...
ArrayData.shared.plantIDForOrganization = Int("\(dic["id"]!)")!
And further, I changed my swift file to this...
public class WebServices {
static let getAllOrganizations: String = "organization/getAllOrganizationDetails/\(ArrayData.shared.plantIDForOrganization)"
}
But by doing this, the value is not properly passed to the API. A 0 is passed to the API instead of the actual id number.
What could be a more efficient way of passing value from my viewcontroller to the swift file..?
When is ArrayData.shared.plantIDForOrganization initialized, and when does WebServices.getAllOganizations get its value? Once the latter is set, it won't "react" to changes in plantIDForOrganization.
I suggest you change this to a computed property, like so:
public class WebServices {
static var getAllOrganizations: String {
return "organization/getAllOrganizationDetails/\(ArrayData.shared.plantIDForOrganization)"
}
}
Also, try to eliminate thos force-unwrapping from your code.
If you have to pass a parameter use a static method instead:
public class WebServices {
static func getAllOrganizations(id: String) -> String { "organization/getAllOrganizationDetails/\(id)" }
}

Binding Protocols with Associated Objects - Protocol Oriented Programming with Swift

i'm an iOS dev with a couple of years of experience with swift, but rarely i've used PAT's...
This time, I was trying to move some code from an app that i've developed to a shared library that I use in a couple of projects. The case is about a Factory that uses various Builders (that are decorators of my business resources) via an Abstract Builder protocol, to obtain Items (in the real case, ViewControllers).
The Builder relays upon some variables that the Factory passes to him, but those are at the application level, so, to extract this logic and put it into my library, i need to use a generic reference, and because I want to work in a Protocol Oriented Programming manner, it is an AssociatedType.
// The item that i want to receive from my factory
protocol Item {
var content: String { get }
}
// This is the Builder interface that the Factory consumes
protocol Builder {
// The Abstract Parameters that the Application should define
associatedtype Parameters
func build(_ parameters: Parameters) -> Item?
}
// The BusinessResource of my library
protocol BusinessResource { }
// The Factory that consumes the Builders
protocol Factory {
associatedtype FactoryBuilder: Builder
var parameters: FactoryBuilder.Parameters { get }
func make(from businessResource: BusinessResource) -> Item?
}
// The generic implementation of my Factory
extension Factory {
func make(from businessResource: BusinessResource) -> Item? {
guard let builder = businessResource as? FactoryBuilder else {
return nil
}
return builder.build(self.parameters)
}
}
At this point everything looks good.
I have two protocols and those are binded together, sharing a common type who is generic (the Builder Parameters).
So, on the application layer, now i could introduce my concrete Parameters (i'll call them ConcreteParameters XD)
// The concrete parameters of the Application Factory
struct ConcreteParameters {
let string: String
}
// The Builder interface restricting Parameters to ConcreteParameters
protocol BindedBuilder: Builder where Parameters == ConcreteParameters {
}
// The Factory interface restricting Parameters to ConcreteParameters
protocol BindedFactory: AbstractFactory where FactoryParameters: ConcreteParameters {
}
So far, so good. Everything looks in place and I'm start thinking that this could work, so now i try to implement a concrete Factory on the application to try if this really works.
// The concrete output of my Builder
struct ConcreteItem: Item {
var content: String
}
// The concrete BusinessResource that i get from my library
struct ConcreteObject: BusinessResource {
let string: String
}
// The decoration extension that makes ConcreteObject compliant with Builder
extension ConcreteObject: Builder {
typealias Parameters = ConcreteParameters
func build(_ parameters: ConcreteParameters) -> Item? {
return ConcreteItem(content: parameters.string + self.string)
}
}
// The real Factory inside my app
class ConcreteFactory: BindedFactory {
typealias FactoryBuilder = BindedBuilder
var parameters: ConcreteParameters {
return ConcreteParameters(string: "Hello ")
}
}
let item = ConcreteFactory().make(from: ConcreteObject(string: "world!"))
print(item ?? "NOT WORKING")
At this point something breaks... I get this error:
[EDIT: Error came from a previous version of the snippet, AbstractFactori is current Factory]
It is a Bug??
I really don't know how to solve this...
I think in this case you need to use a concrete type to alias FactoryBuilder instead of BindedBuilder, as protocols do not conform to themselves.
This code effectively compiles, would something like that match your requirements?
class ConcreteFactory: BindedFactory {
typealias FactoryBuilder = ConcreteObject
var parameters: ConcreteParameters {
return ConcreteParameters(string: "Hello ")
}
}
Otherwise you can also try type erasing BindedBuilder and create AnyBindedBuilder, as suggested in the same link.

Where to put reusable functions in IOS Swift?

New to IOS programming but just wondering where is the best place to put functions that I would use throughout my code. For example, I want to write a few functions to perform a POST request to a web service and return a dictionary. Maybe another function to do some calculations. Is it best to create another .swift file and put all my functions there. And what would be a good name to give the file if so?
public func postRequest() -> [String:String] {
// do a post request and return post data
return ["someData" : "someData"]
}
The best way is to create a helper class with static functions, like this:
class Helper{
static func postRequest() -> [String:String] {
// do a post request and return post data
return ["someData" : "someData"]
}
}
Now every time you need to use postRequest you can just use like so: Helper.postRequest()
I usually create a separate class if I have functions that will be used by multiple classes, especially for the ones involving network operations.
If you just have separate functions that will be used, you can simply create static functions inside that class so it is easily accessible by other classes in a static way:
class DataController {
static func getData() -> [String:String] {
// do some operations
return ["someData" : "someData"]
}
}
let data = DataController.getData() // example
However, what often has been the case for me (especially if it involves more complicated operations) was that these network operations needed to establish an initial connection beforehand or required some initial setups, and they also performed asynchronous operations that needed to be controlled. If this is the case and you will often be calling such methods, you might want to create a singleton object that you could use throughout different classes and functions. This way, you could do the initial setup or establish an initial connection just once, and then do the rest as needed with the other functions, instead of doing them every time the function gets called.
Creating a singleton object is pretty simple in Swift:
class DataController {
static let sharedInstance = DataController() // singleton object
init() {
// do initial setup or establish an initial connection
}
func getData() -> [String:String] {
// do some operations
return ["someData" : "someData"]
}
}
let data = DataController.sharedInstance.getData() // example
For the name of the class, I usually name it something like DataController or DataHelper, but anything that makes sense as a "helper" class would work.
Hope this helps :)
For reusable functions it depends what I decide to use. For this specific case I use a separate file, because posting to a backend will become more complicated when the application evolves. In my app I use a backend class, with all kinds of helper classes:
struct BackendError {
var message : String
}
struct SuccessCall {
var json : JSON
var containsError : Bool {
if let error = json["error"].string {
return true
}
else {
return false
}
}
}
typealias FailureBlock = (BackendError) -> Void
typealias SuccessBlock = (SuccessCall) -> Void
typealias AlamoFireRequest = (path: String, method: Alamofire.Method, data: [String:String]) -> Request
typealias GetFunction = (path: String , data: [String : String], failureBlock: FailureBlock, successBlock: SuccessBlock) -> Void
class Backend {
func getRequestToBackend (token: String )(path: String , data: [String : String], failureBlock: FailureBlock, successBlock:
}
For other cases I often use extensions on Swift classes. Like for getting a random element from an Array.
extension Array {
func sampleItem() -> T {
let index = Int(arc4random_uniform(UInt32(self.count)))
return self[index]
}
}
This very old question but I would like to chirp some more points.
There are a few option, basically you can write your utility functions in Swift -
A class with static function. For example
class CommonUtility {
static func someTask() {
}
}
// uses
CommonUtility.someTask()
Also, you can have class method's as well instead of static method but those functions can be overridden by subclasses unlike static functions.
class CommonUtility {
class func someTask() {
}
}
// uses
CommonUtility.someTask()
Secondly, you can have Global functions as well, that are not part of any class and can be access anywhere from your app just by name.
func someTask() {
}
Though, selecting one over other is very subjective and I thing this is ok to make a class with static function in this particular case, where you need to achieve networking functionality but if you have some functions which perform only one task than Global function is a way to go because Global functions are more modular and separate out single tasks for a single function.
In case of static functions, if we access one of the static member, entire class gets loaded in memory. But in case of global function, only that particular function will be loaded in mem
You can create a separate swift class, might name it WebServicesManager.swift, and write all methods related to web requests in it.
You can use class methods, or singleton pattern to access the methods.

How to use generic protocol as a variable type

Let's say I have a protocol :
public protocol Printable {
typealias T
func Print(val:T)
}
And here is the implementation
class Printer<T> : Printable {
func Print(val: T) {
println(val)
}
}
My expectation was that I must be able to use Printable variable to print values like this :
let p:Printable = Printer<Int>()
p.Print(67)
Compiler is complaining with this error :
"protocol 'Printable' can only be used as a generic constraint because
it has Self or associated type requirements"
Am I doing something wrong ? Anyway to fix this ?
**EDIT :** Adding similar code that works in C#
public interface IPrintable<T>
{
void Print(T val);
}
public class Printer<T> : IPrintable<T>
{
public void Print(T val)
{
Console.WriteLine(val);
}
}
//.... inside Main
.....
IPrintable<int> p = new Printer<int>();
p.Print(67)
EDIT 2: Real world example of what I want. Note that this will not compile, but presents what I want to achieve.
protocol Printable
{
func Print()
}
protocol CollectionType<T where T:Printable> : SequenceType
{
.....
/// here goes implementation
.....
}
public class Collection<T where T:Printable> : CollectionType<T>
{
......
}
let col:CollectionType<Int> = SomeFunctiionThatReturnsIntCollection()
for item in col {
item.Print()
}
As Thomas points out, you can declare your variable by not giving a type at all (or you could explicitly give it as type Printer<Int>. But here's an explanation of why you can't have a type of the Printable protocol.
You can't treat protocols with associated types like regular protocols and declare them as standalone variable types. To think about why, consider this scenario. Suppose you declared a protocol for storing some arbitrary type and then fetching it back:
// a general protocol that allows for storing and retrieving
// a specific type (as defined by a Stored typealias
protocol StoringType {
typealias Stored
init(_ value: Stored)
func getStored() -> Stored
}
// An implementation that stores Ints
struct IntStorer: StoringType {
typealias Stored = Int
private let _stored: Int
init(_ value: Int) { _stored = value }
func getStored() -> Int { return _stored }
}
// An implementation that stores Strings
struct StringStorer: StoringType {
typealias Stored = String
private let _stored: String
init(_ value: String) { _stored = value }
func getStored() -> String { return _stored }
}
let intStorer = IntStorer(5)
intStorer.getStored() // returns 5
let stringStorer = StringStorer("five")
stringStorer.getStored() // returns "five"
OK, so far so good.
Now, the main reason you would have a type of a variable be a protocol a type implements, rather than the actual type, is so that you can assign different kinds of object that all conform to that protocol to the same variable, and get polymorphic behavior at runtime depending on what the object actually is.
But you can't do this if the protocol has an associated type. How would the following code work in practice?
// as you've seen this won't compile because
// StoringType has an associated type.
// randomly assign either a string or int storer to someStorer:
var someStorer: StoringType =
arc4random()%2 == 0 ? intStorer : stringStorer
let x = someStorer.getStored()
In the above code, what would the type of x be? An Int? Or a String? In Swift, all types must be fixed at compile time. A function cannot dynamically shift from returning one type to another based on factors determined at runtime.
Instead, you can only use StoredType as a generic constraint. Suppose you wanted to print out any kind of stored type. You could write a function like this:
func printStoredValue<S: StoringType>(storer: S) {
let x = storer.getStored()
println(x)
}
printStoredValue(intStorer)
printStoredValue(stringStorer)
This is OK, because at compile time, it's as if the compiler writes out two versions of printStoredValue: one for Ints, and one for Strings. Within those two versions, x is known to be of a specific type.
There is one more solution that hasn't been mentioned on this question, which is using a technique called type erasure. To achieve an abstract interface for a generic protocol, create a class or struct that wraps an object or struct that conforms to the protocol. The wrapper class, usually named 'Any{protocol name}', itself conforms to the protocol and implements its functions by forwarding all calls to the internal object. Try the example below in a playground:
import Foundation
public protocol Printer {
typealias T
func print(val:T)
}
struct AnyPrinter<U>: Printer {
typealias T = U
private let _print: U -> ()
init<Base: Printer where Base.T == U>(base : Base) {
_print = base.print
}
func print(val: T) {
_print(val)
}
}
struct NSLogger<U>: Printer {
typealias T = U
func print(val: T) {
NSLog("\(val)")
}
}
let nsLogger = NSLogger<Int>()
let printer = AnyPrinter(base: nsLogger)
printer.print(5) // prints 5
The type of printer is known to be AnyPrinter<Int> and can be used to abstract any possible implementation of the Printer protocol. While AnyPrinter is not technically abstract, it's implementation is just a fall through to a real implementing type, and can be used to decouple implementing types from the types using them.
One thing to note is that AnyPrinter does not have to explicitly retain the base instance. In fact, we can't since we can't declare AnyPrinter to have a Printer<T> property. Instead, we get a function pointer _print to base's print function. Calling base.print without invoking it returns a function where base is curried as the self variable, and is thusly retained for future invocations.
Another thing to keep in mind is that this solution is essentially another layer of dynamic dispatch which means a slight hit on performance. Also, the type erasing instance requires extra memory on top of the underlying instance. For these reasons, type erasure is not a cost free abstraction.
Obviously there is some work to set up type erasure, but it can be very useful if generic protocol abstraction is needed. This pattern is found in the swift standard library with types like AnySequence. Further reading: http://robnapier.net/erasure
BONUS:
If you decide you want to inject the same implementation of Printer everywhere, you can provide a convenience initializer for AnyPrinter which injects that type.
extension AnyPrinter {
convenience init() {
let nsLogger = NSLogger<T>()
self.init(base: nsLogger)
}
}
let printer = AnyPrinter<Int>()
printer.print(10) //prints 10 with NSLog
This can be an easy and DRY way to express dependency injections for protocols that you use across your app.
Addressing your updated use case:
(btw Printable is already a standard Swift protocol so you’d probably want to pick a different name to avoid confusion)
To enforce specific restrictions on protocol implementors, you can constrain the protocol's typealias. So to create your protocol collection that requires the elements to be printable:
// because of how how collections are structured in the Swift std lib,
// you’d first need to create a PrintableGeneratorType, which would be
// a constrained version of GeneratorType
protocol PrintableGeneratorType: GeneratorType {
// require elements to be printable:
typealias Element: Printable
}
// then have the collection require a printable generator
protocol PrintableCollectionType: CollectionType {
typealias Generator: PrintableGenerator
}
Now if you wanted to implement a collection that could only contain printable elements:
struct MyPrintableCollection<T: Printable>: PrintableCollectionType {
typealias Generator = IndexingGenerator<T>
// etc...
}
However, this is probably of little actual utility, since you can’t constrain existing Swift collection structs like that, only ones you implement.
Instead, you should create generic functions that constrain their input to collections containing printable elements.
func printCollection
<C: CollectionType where C.Generator.Element: Printable>
(source: C) {
for x in source {
x.print()
}
}

Swift - Typealias dictionary with value that implements a generic protocol

I want to typealias a dictionary of String keys and values of objects/structs that implements the Equatable protocol. So I wrote this line of code but it gave me error that I didn't know how to go on to fix.
typealias Storage = [String: Equatable]
I want to use the type [String: Equatable] as a variable in a protocol, e.g:
protocol StorageModel {
var storage: Storage { get set }
init(storage: Storage)
}
Error:
Protocol 'Equatable' can only be used as a generic constraint because
it has Self or associated type requirements
Can anyone suggest a solution?
Generally speaking, the protocol tag isn't required, protocol names are first-class type names and can be used directly:
typealias Storage = [String:Equatable]
In this case, what the error is telling you is that because Equatable includes func == (lhs:Self, rhs:Self) -> Bool and specifically lhs:Self, Equatable can't be used except as a constraint on a generic:
class Generic<T:Equatable> { ... }
Without more details about what you're trying to achieve and how you're trying to use StorageModel, the best I can come up with is:
protocol Matches {
typealias T
func matches(t:T) -> Bool
}
protocol StorageModel {
typealias T
var storage: [String:T] { get set }
init(storage:[String:T])
}
extension Int : Matches {
func matches(target:Int) -> Bool {
return self == target
}
}
class MyClass <T:Matches> {
var model = [String:T]()
}
Another possibility is to use a generic instead of a protocol:
class StorageModel <T:Equatable> {
var storage: [String:T]
init(storage:[String:T]) {
self.storage = storage
}
}
From there you'll need to do some research, dig into the Swift manual, do some googling and see what solves your problem.

Resources