2

I have the following struct

struct APIResource<T> {
    let urlRequest: NSMutableURLRequest
    let resource: T
    let parse: (NSData) -> T
 }

I also have the following view controller. It's job it is to ask the network stack to load the resource from the network. Once it is done, it will call the build function to build the appropriate view controller and adds it as a child view controller

 final class LoadingVCL: UIViewController {

init<T>(_ resources: APIResource<T>, build: ((T) -> UIViewController)) {
    super.init(nibName: nil, bundle: nil)
    //ask the network stack for the data
    //once data is loaded, I call the build closure 
    //to return a view controller and add it as a childviewcontroller
}

I am struggling to extend this LoadingVC to accept an array of resources and load them before adding the view controller.

I came across this when following this tutorial.

Edit One

For Instance, suppose I have the following resources

let resourceOne = APIResource<Int>(urlRequest: NSMutableURLRequest(), resource: 1, parse: { _ in return 1})
let resourceTwo = APIResource<Double>(urlRequest: NSMutableURLRequest(), resource: 1, parse: { _ in return 1})
let resourceThree = APIResource<String>(urlRequest: NSMutableURLRequest(), resource: "1", parse: { _ in return "1"})

I am trying to figure out a way for the view controller to accept an array of resources with different types.

Any help would be appreciated. Thanks

5
  • You definitely should not be loading content from the network in a view controller. Regardless, what's your actual issue? Commented Dec 3, 2016 at 7:02
  • 1
    Custom initializers for UIViewController subclasses don't typically work since you will often use a storyboard scene or nib which uses init(coder) also combining a generic with a ViewController doesn't make a lot of sense. Commented Dec 3, 2016 at 8:13
  • @Alexander I use a network stack to load the data. sorry for not putting that on question description as well. I have updated the question with my issue. Commented Dec 3, 2016 at 8:31
  • @Paulw11. In the demo app I am building, I am not using storyboard. also, all viewcontrollers display data that's coming from the network. using the loadingviewcontroller would hide the networking code form all the other viewcontrollers. you could look at this tutorial that explains this approach. Commented Dec 3, 2016 at 8:43
  • I looked at the tutorial. I don't think it is a good approach. It tightly couples network operations, data model and view controller into the one class. Performing network operations in init is also a bad idea Commented Dec 3, 2016 at 9:12

1 Answer 1

1

As soon as an instance of APIResource<T> is created it has an assigned type and is no longer generic. APIResource<String>, for example, is of a different type to APIResource<Double>. To create an array of mixed types you'll need to use a protocol, e.g.

protocol APIResourceProtocol{}
struct APIResource<T>:APIResourceProtocol {
    let urlRequest: NSMutableURLRequest
    let resource: T
    let parse: (NSData) -> T
}

let resourceOne = APIResource<Int>(urlRequest: NSMutableURLRequest(), resource: 1, parse: { _ in return 1})
let resourceTwo = APIResource<Double>(urlRequest: NSMutableURLRequest(), resource: 1, parse: { _ in return 1})
let resourceThree = APIResource<String>(urlRequest: NSMutableURLRequest(), resource: "1", parse: { _ in return "1"})

let arr:[APIResourceProtocol] = [resourceOne, resourceTwo, resourceThree]

Of course this probably isn't what you want because you're probably wanting to be able to go through an array and use certain methods. Unfortunately, protocols are not generic so it will only be non-generic types that you can leverage this type of behaviour with, e.g.

protocol APIResourceProtocol {
    var urlRequest: NSMutableURLRequest {get set}
}

struct APIResource<T>:APIResourceProtocol {
    var urlRequest: NSMutableURLRequest
    let resource: T
    let parse: (NSData) -> T
}

protocol ResourceType {}

let resourceOne = APIResource<Int>(urlRequest: NSMutableURLRequest(), resource: 1, parse: { _ in return 1})
let resourceTwo = APIResource<Double>(urlRequest: NSMutableURLRequest(), resource: 1, parse: { _ in return 1})
let resourceThree = APIResource<String>(urlRequest: NSMutableURLRequest(), resource: "1", parse: { _ in return "1"})

let arr:[APIResourceProtocol] = [resourceOne, resourceTwo, resourceThree]

arr.map{$0.urlRequest}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.