Alternative to the load class method

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Alternative to the load class method

Tron Thomas
I am working on developing an application in Swift. I wanted to design a system for the application that allowed for loose coupling between objects, and one strategy (which I have used successfully in other languages) was to create something I call an instance factory. It is pretty simple and here is the basic implementation I came up with in Swift:

import Foundation

private var typeGenerators = Dictionary<String, InstanceFactory.GeneratorCallback>()

public class InstanceFactory: NSObject {
   
public typealias GeneratorCallback = () -> AnyObject!

   
public class func registerGeneratorFor(typeName: String, callback: GeneratorCallback) {
        typeGenerators
[typeName] = callback
   
}
   
   
public class func instanceOf(typeName: String) -> AnyObject! {
       
return typeGenerators[typeName]?()
   
}
}

The idea is that when an object instance needs access to another object instance, rather than creating that instance outright which would more tightly couple the two objects, the first object would defer to the factory to provide the needed instance by calling the instanceOf method. The factory would know how to provide various instance types because those types would register with the factory and provide a closure that could generate the instance.

The trick is how to  get the classes to register with the factory. I had previously made a similar factory in Objective-C and the way I got registration to work was to override the +load method for each class that needed to register with the factory. This worked great for Objective-C, and I figured it could work for Swift as well since I would be restricting the factory to only provide objects that are derived from NSObject. It appeared I got this to work and I spent a significant about of effort designing classes to make use of the factory.

However, after upgrading to Xcode 6.3, I discovered Apple has disallowed the usage of the load class method in Swift. Without this, I am unaware of a mechanism to allow classes to automatically register themselves with the factory.

I am wondering if there some other way to get the registration to work.

What alternatives are available that could allow classes to register with the factory, or what other techniques could be use to accomplish the same kind of loose coupling the factory provides?

--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/20179d9f-8b35-4580-99fe-a9fc8c7bc189%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Alternative to the load class method

Sam Stigler
I generally just use protocols for loose coupling. Have you looked into them at all? You can have your classes conform to one or more of them, and then type properties as the a protocol instead of a specific class.

Sam

On Apr 18, 2015, at 11:48 AM, Tron Thomas <[hidden email]> wrote:

I am working on developing an application in Swift. I wanted to design a system for the application that allowed for loose coupling between objects, and one strategy (which I have used successfully in other languages) was to create something I call an instance factory. It is pretty simple and here is the basic implementation I came up with in Swift:

import Foundation

private var typeGenerators = Dictionary<String, InstanceFactory.GeneratorCallback>()

public class InstanceFactory: NSObject {
   
public typealias GeneratorCallback = () -> AnyObject!

   
public class func registerGeneratorFor(typeName: String, callback: GeneratorCallback) {
        typeGenerators
[typeName] = callback
   
}
   
   
public class func instanceOf(typeName: String) -> AnyObject! {
       
return typeGenerators[typeName]?()
   
}
}

The idea is that when an object instance needs access to another object instance, rather than creating that instance outright which would more tightly couple the two objects, the first object would defer to the factory to provide the needed instance by calling the instanceOf method. The factory would know how to provide various instance types because those types would register with the factory and provide a closure that could generate the instance.

The trick is how to  get the classes to register with the factory. I had previously made a similar factory in Objective-C and the way I got registration to work was to override the +load method for each class that needed to register with the factory. This worked great for Objective-C, and I figured it could work for Swift as well since I would be restricting the factory to only provide objects that are derived from NSObject. It appeared I got this to work and I spent a significant about of effort designing classes to make use of the factory.

However, after upgrading to Xcode 6.3, I discovered Apple has disallowed the usage of the load class method in Swift. Without this, I am unaware of a mechanism to allow classes to automatically register themselves with the factory.

I am wondering if there some other way to get the registration to work.

What alternatives are available that could allow classes to register with the factory, or what other techniques could be use to accomplish the same kind of loose coupling the factory provides?

--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/20179d9f-8b35-4580-99fe-a9fc8c7bc189%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/43EDF410-0CA7-497B-9CC6-026AE1F8C597%40gmail.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Alternative to the load class method

Jens Alfke
In reply to this post by Tron Thomas

On Apr 18, 2015, at 9:48 AM, Tron Thomas <[hidden email]> wrote:

The trick is how to  get the classes to register with the factory. I had previously made a similar factory in Objective-C and the way I got registration to work was to override the +load method for each class that needed to register with the factory.

This works, but the reason +load is semi-deprecated is that it causes all of those classes to be initialized before your main( ) function runs, which causes extra work to happen at launch time, so it makes your app take longer to start up (and increases its initial memory footprint.) It’s also prone to weird random bugs because the order in which classes load is not deterministic and can vary from one run to the next, and if one class’s +load method invokes another class, it’s possible to end up with cycles where a class gets called before its +load method has run.

However, after upgrading to Xcode 6.3, I discovered Apple has disallowed the usage of the load class method in Swift. Without this, I am unaware of a mechanism to allow classes to automatically register themselves with the factory.

It feels to me like the registration is an app-global decision, not something left up to each specific class. For instance, what if there are two classes that provide the same typename? In your implementation they’d conflict — both would register for the same name and one would override the other (totally at random, depending on the order the runtime loads classes.) Ouch.

That may sound like a fake problem to you — “why would I make two classes that both provide the same type?” — but consider if this registry became a shared utility framework. Loose coupling is obviously useful when assembling modules from different developers. But in this case your app might link in 3rd party modules that happen to include classes that provide the same service type. Now you have a conflict.

For that reason I think it’s best if some central code (like your app delegate) does the registration at startup time. (And of course it can delegate part of that task to subsystems by calling a subsystem’s method to register the types that subsystem provides.)

—Jens

--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/C28DCD7C-CFF9-479A-8569-4840FA1AAB9C%40mooseyard.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Alternative to the load class method

Jens Alfke
In reply to this post by Sam Stigler

On Apr 18, 2015, at 10:28 AM, Sam Stigler <[hidden email]> wrote:

I generally just use protocols for loose coupling. Have you looked into them at all? You can have your classes conform to one or more of them, and then type properties as the a protocol instead of a specific class.

Yeah, but that doesn’t help you instantiate (or otherwise acquire) an instance of the protocol. For that you need a factory, like what Tron is using.

This is a standard design pattern — I think it’s called the Factory or Registry. Try looking it up, i.e. in the Gang Of Four book (Gamma et al) and see if there’s a discussion of the best way to initialize the registry.

—Jens

--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/F59B5A0C-6A7F-4227-BF20-550C6E4B324C%40mooseyard.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Alternative to the load class method

Sam Stigler
I'm aware of what the factory pattern is, but I'm honestly failing to see the connection between that and the need to register classes to be returned by it. How I generally use it I have a factory instance (for example, "ScreenFactory" that returns instances of a shared superclass. No one outside of the factory needs to know the details of how that instance was created.

I've never tried this with protocols in Swift, but I imagine it would work the same way. Is there something I'm missing here? From my brief skim of the Wikipedia article on the Factory pattern, it seems like my idea of it may be different from the more widely-accepted idea of it.

Sam

On Apr 18, 2015, at 12:36 PM, Jens Alfke <[hidden email]> wrote:


On Apr 18, 2015, at 10:28 AM, Sam Stigler <[hidden email]> wrote:

I generally just use protocols for loose coupling. Have you looked into them at all? You can have your classes conform to one or more of them, and then type properties as the a protocol instead of a specific class.

Yeah, but that doesn’t help you instantiate (or otherwise acquire) an instance of the protocol. For that you need a factory, like what Tron is using.

This is a standard design pattern — I think it’s called the Factory or Registry. Try looking it up, i.e. in the Gang Of Four book (Gamma et al) and see if there’s a discussion of the best way to initialize the registry.

—Jens

--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/FDE877C9-A6BE-4FB4-A16A-4B7E821A66AB%40gmail.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Alternative to the load class method

Jens Alfke

On Apr 18, 2015, at 11:08 AM, Sam Stigler <[hidden email]> wrote:

How I generally use it I have a factory instance (for example, "ScreenFactory" that returns instances of a shared superclass. No one outside of the factory needs to know the details of how that instance was created.

The differences in Tron’s design are that 
  • it provides multiple types/classes; instead of a fixed ScreenFactory it ca provide arbitrary types based on the input.
  • the mapping from type (or protocol) to implementation class is not managed by the factory itself. In his implementation each class controls which type it’s registered for. I was suggesting a separate initializer in e.g. the app delegate.

It’s still a factory, it’s just that the internal logic about what class to instantiate is different than it is in your implementation. I might call it more of a Registry.

—Jens

--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/4892F8E2-E6FB-4CFA-8ABC-546D9C433DA1%40mooseyard.com.
For more options, visit https://groups.google.com/d/optout.