Typhoon lazy injection in Swift - ios

While trying and playing around with Typhoon DI, I realized that LazySingleton scope is not working as expected meaning lazy properties are injected even before they are used. Being more concrete I created a TyphoonAssembly as follow :
public class AppAssembly : TyphoonAssembly {
public dynamic func knight() -> AnyObject{
return TyphoonDefinition.withClass(Knight.self){
(definition) in
definition.injectProperty("name", with: "Dragon")
definition.injectProperty("horse")
definition.scope = TyphoonScope.LazySingleton
}
}
public dynamic func horse() -> AnyObject{
return TyphoonDefinition.withClass(Horse.self){
(definition) in
definition.injectProperty("color", with: "red")
definition.scope = TyphoonScope.LazySingleton
}
}
}
where Knight is NSObject and has validateProperties function
class Knight:NSObject {
var name:String?
var horse: Horse?
func validateProperties(){
if name != nil{
println("Name not nil")
}
if horse != nil{
println("Horse not nil")
}
}
}
After activating assembly and getting knight from it, calling validateProperties function always print Name not nil and Horse not nil even these properties are never used in my code. Am I missing something here or simply lazy injection does not work same as Swift lazy stored properties do?

Your interpretation of the term lazy singleton makes sense, but its not the correct one. TyphoonScopeLazySingleton means that Typhoon won't instantiate the whole object until its asked for. Once asked for all properties will be injected. There's no proxying to inject on demand - if you're interested in such a feature, would you mind raising an issue for us in Github?
You're right that such a feature would only work in Swift if the class extended NSObject and the properties were types compatible with Objective-C, as "pure" Swift uses C++ style static dispatch, and therefore runtime method interception/proxying is not possible.
Here's the user guide for Typhoon scopes.

Related

Testing protocol extension with default implementations

In past projects, I've had an object use constructor injection for the objects it needs to get some other information. For example:
class Foo {
let appInfo: AppInfoType
init(appInfo: AppInfoType) {
self.appInfo = appInfo
}
}
protocol AppInfoType {
func build(bundle: Bundle) -> String?
}
And then if within Foo, information about the app like build is needed, it can use AppInfoType to get that info. I thought I would see what this looked like with protocol extensions.
extension AppInfoType {
func build(bundle: Bundle) -> String? {
return bundle.infoDictionary?[kCFBundleVersionKey as String] as? String
}
}
class Foo: AppInfoType {
}
So now I can achieve the same thing within Foo by just calling build(bundle: Bundle.main). But is there any easy way to test this now? With the first way, I could still create a MockAppInfoType and provide an implementation for build(bundle: Bundle), but now I don't really see a way to do this unless the protocol extension maybe depended on another protocol where I could inject a mock for that protocol.

Infer Generic Type in Class Method with Swift

Is it possible for a generic method to infer its type based on the class in which it is being executed? I use CoreData NSManagedObject models to store and retrieve local data, and have managed to make everything generic in an easy to read and usable way, except for in one place. If a user wishes to query the local database to fetch a list of objects, he would write the following line:
let posts: [Post] = Post.all()
This will properly return "all" Post objects in the database, but the syntax requires that the type be defined ([Post]) on top of calling the method from the Post class itself (Post.all()), which feels unnecessarily redundant. Is there any way to define the generic type simply by calling the all() method from the Post class? I imagine I could just create global functions for fetching data, like so:
let posts: [Post] = all()
This doesn't feel nearly as readable as it would be if the syntax was as follows:
let posts = Post.all()
The point of trying to improve this is so that any developers who pick up this project can quickly learn the structure and style without much effort. Also, this will hopefully increase general code readability in the future, regardless of if someone is working on it or just reading it for some other reason.
For more insight, here is a bit more information about the current structure:
//Model.swift - The model base class. All models extend this class.
class Model: NSManagedObject {
/**
Some other stuff here
**/
//MARK: Fetch
internal class func fetch<T: Model>(predicate: NSPredicate? = nil) -> [T]? {
do {
if let request = NSFetchRequest.FromEntityName(self.entityName) { //Get entity with the name defined in the current class
request.predicate = predicate
if let result = try self.context?.executeFetchRequest(request) as? [T] {
return result
}
}
}
catch let error as NSError {
Log.Error("\(error)")
}
return nil
}
//MARK: Fetch general
class func all<T: Model>() -> [T]? {
if let result: [T] = self.fetch() {
return result
}
Log.warning("No \(self.entityName) found")
return nil
}
}
//Post.swift - An example model class. Extends Model.swift
class Post: Model {
//some fields
}
//Example view controller
class ViewController: UIViewController {
override func viewDidLoad() {
let posts: [Post] = Post.all()
//do stuff
}
}
If anyone has an idea about then please let me know. All help is appreciated!
In the general case, the typical way for a class method to return "type of the class" even for subclasses is to use protocol extensions and the Self type. Here's an example that boils your approach down to the bare minimum to make the type checking work the way you want:
// define a protocol
protocol ModelType {}
// create a static method on the protocol that returns [Self]
extension ModelType where Self: NSManagedObject {
static func all() -> [Self]? {
return [Self]() // do your fetch here
}
}
// conform to the protocol in your class hierarchy
class Model: NSManagedObject, ModelType {}
class Post: Model {}
let posts = Post.all()
// implicit type of `posts` is `[Post]?`
Note that all() should be provided by the protocol extension, but not a requirement of the protocol. If you declare all() inside protocol ModelType, then you can't make it use dynamic dispatch, which is necessary if it's to use a dynamic type.
Also, note that in Swift 3 (and macOS 10.12 / iOS 10 / tvOS 10 / watchOS 3), Core Data itself defines some Swift API shortcuts that replace some of the ones you've defined for yourself. Note this example from What's New in Core Data:
func findAnimals() {
context.performAndWait({
let request = Animal.fetchRequest // implicitly NSFetchRequest<Animal>
do {
let searchResults = try request.execute()
// use searchResults ...
} catch {
print("Error with request: \(error)")
}
})
}
Finally, some commentary on your choice of style...
fyi I capitalize the first letter in all static/class methods just as a convention
The point of trying to improve this is so that any developers who pick up this project can quickly learn the structure and style without much effort. Also, this will hopefully increase general code readability in the future
I'm not sure that breaking from language-standard conventions (like the lowercase method names recommended in the Swift 3 API Guidelines) is very compatible with your goal of making it easy for other developers new to your codebase to read and participate.

Alternative to smelly global variables in Swift?

I've defined a global struct with static properties with values I use in many of my view controllers, like this:
public struct AppGlobal {
static var currentUser = UserModel()
static let someManager = SomeManager()
// Prevent others from initializing
private init() { }
}
Then in my UIViewController, I can do something like this:
class MyController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
AppGlobal.currentUser.prop1 = "abc123"
AppGlobal.someManager.startUpdating()
}
}
This is obviously very convenient, but smells really bad. I believe dependency injection would come in handy here, but not sure how. Is there a more elegant alternative to creating the AppGlobal singleton properties?
I can't see why you need to access userModel or someManager through a global state (and yes — Singletons are just that).
Why not just set it where you need it?
"Dependency Injection" is a 25-dollar term for a 5-cent concept.
That's not to say that it's a bad term…
[…]
Dependency injection means
giving an object its instance variables. Really. That's it.
– James Shore: Dependency Injection Demystified
Either do it during constructing
class C {
let currentUser: UserModel
let someManager: SomeManager
init(currentUser:UserModel, someManger:SomeManager) {
self.currentUser = currentUser
self.someManager = someManager
}
}
or through properties. If you need to make sure that all properties are set, do something like this:
class MyController: UIViewController {
var currentUser: UserModel? {
didSet{
self.configureIfPossible()
}
}
var someManager: SomeManager?{
didSet{
self.configureIfPossible()
}
}
func configureIfPossible(){
if let currentUser = self.currentUser, someManager = self.someManager {
// configure
}
}
}
In my current project we have the policy that every dependency must be visible and configurable from outside the class.
An example:
class LibrarySegmentViewController: BaseContentViewController {
var userDefaults: NSUserDefaults?
var previousSorting : LibrarySortingOrder = .AZ
var sorting : LibrarySortingOrder {
set{
self.previousSorting = sorting
if let filterMode = self.filterMode {
self.userDefaults?.setInteger(newValue.rawValue, forKey: "\(filterMode)_LibrarySorting")
}
self.setupIfReady()
}
get{
if let filterMode = self.filterMode {
if let s = LibrarySortingOrder(rawValue: self.userDefaults!.integerForKey("\(filterMode)_LibrarySorting")) {
return s
}
}
return .Date
}
}
}
So as you can see, we even use properties to reference NSUserDefaults.standardUserDefaults(). We do this as we can pass in fresh instances during testing, without bigger mocking hassle.
And this is the most importing reason why not to use singletons directly: The dependencies are hidden and might bite you during testing and refactoring. Another example would be an API client singleton that is hidden in the code and performs unwanted networking requests during testing. If it is set from outside of the tested class you can just pass in a mocked networking client that does not perform any requests but returns test data.
So even if you use singletons, you should pass it in as a dependencies.
If this question is about global or not, you should see this thread :
What is so bad about singletons?
But if you want a better design for your implementation of a singleton you can try something like this :
class SingletonExample: NSObject {
static let sharedInstance: SingletonExample()
}
class OtherSingletonExample: NSObject {
static let sharedInstance: OtherSingletonExample()
}
Then you can use SingletonExample.sharedInstance and OtherSingletonExample.sharedInstance anywhere in your code.
The idea is to isolate one singleton from another and access it as a class attribute instead of creating a big global struct for anything.

Singleton in one line on Swift 2.0

Please help me with Swift,
I need singleton with can inheritance.
I can do like this
class A {
var defaultPort: Int
required init() {
self.defaultPort = 404
}
class var defaultClient: A {
struct Static {
static var onceToken: dispatch_once_t = 0
static var instance: A? = nil
}
dispatch_once(&Static.onceToken) {
Static.instance = self.init()
}
return Static.instance!
}
}
but in swift 2.0 we can do like this
static let defaultClient = A() //self.init()
but it creates an instance of the class A any way.
How i can use like this self.init()
static let defaultClient = self.init()
in order to be able to inherit
UPD
best way for now
class A {
class func defaultClient() -> Self {
struct Static {
static var onceToken: dispatch_once_t = 0
static var instance: A? = nil
}
dispatch_once(&Static.onceToken) {
Static.instance = self.init()
}
return instance(Static.instance, asType: self)
}
}
here we need helper as
func instance<T>(instance: Any, asType type: T.Type) -> T {
let reurnValue = instance as! T
return reurnValue
}
because another way cast A to Self not exist, for now.
p.s. crazy swift way!
why i can not do instance as! Self
Your question isn't very clear. You're looking for something like the class constant solution posted in this answer, but which automatically uses "my own class" instead of explicitly creating an instance of a specific class... right?
That is, you want to turn this:
class Singleton {
static let sharedInstance = Singleton()
}
into this:
class Singleton {
static let sharedInstance = SomeMagicThing()
}
class SingletonSubclass {}
where SomeMagicThing automatically creates a Singleton instance when you call Singleton.sharedInstance, and a SingletonSubclass instance when you call SingletonSubclass.sharedInstance. Correct?
Sorry, that can't be done (as of Swift 2.1).
Part of your issue is that static and class mean two different things. The static modifier means that the declaration it modifies is associated only with a specific type declaration. So, the Singleton type owns a pointer to a specific object -- its subclasses don't inherit that pointer. (And if they did, would it point to the same object or a subclass-specific one?)
If you could create a class var or class let, that'd (in theory) give you the kind of dispatch/inheritance you want. But trying that gives you an error (emphasis mine):
class stored properties not yet supported in classes; did you mean static?
So it sounds like this sort of thing might show up someday.
Of course, the other side of the problem is finding a way to dynamically refer to the "current" type responsible for executing some statement. In the context of an instance method, you have self.dynamicType for such things... but there's no equivalent for classes. (Self is a type constraint, not an actual type.) This is a side effect of the type system in Swift being much more strict and static than that of Objective-C (for example, metatypes aren't just a special flavor of otherwise normal objects). File a bug if you'd like to see a change to that effect?

Swift Compiler SegFault when initializing Object from Type

I am currently working on an iOS app using Swift. I have a custom DataSource that needs to know the Type of the model that it has to provide. I have a custom Protocol, that has one method.
protocol JSONModel {
init(json: JSON)
}
Then, there are several models that implement the protocol. All of them have different properties, but are the same otherwise.
class CurrentDownload: JSONModel {
let someProperty: String
required init(json: JSON) {
someProperty = json["someProperty"].stringValue
}
}
My DataSource has a property that is of type JSONModel.Type
private let modelClass: JSONModel.Type
When i try to initialize a new instance of my modelClass i get a segmentation fault. Initialization of the model is done by
let model = modelClass(json: modelJSON)
Unfortunately, the compiler crashes on that line.
Swift Compiler Error
Command failed due to signal: Segmentation fault: 11
1. While emitting IR SIL function
#_TFC14pyLoad_for_iOS21RemoteTableDataSourceP33_56149C9EC30967B4CD75284CC9032FEA14handleResponsefS0_FPSs9AnyObject_T_ for 'handleResponse' at RemoteTableDataSource.swift:59:13
Does anybody have an idea on how to fix this or on how to work around this issue?
I believe this problem isn't too hard.
Usually with Swift segmentation faults are when you try to set the value of a constant (let) quantity, or try to set the value of something that hasn't been properly declared.
I can spot one such instance here:
required init(json: JSON) {
bytesLeft = json["someProperty"].stringValue
}
There's two things wrong with this example. You have a (designated) initialiser which terminates without setting the property someProperty and you haven't declared the variable bytesLeft.
So now the problem (which I really should have spotted before) is that * modelClass* just is not a class (or otherwise initialisable type). To cannot directly access a protocol, you can only access a class conforming to a protocol. The compiler didn't spot this because you did something sneaky with .Type.
When I say access, I mean functions and properties, including initialisers.
Only a class can create an instance of a class, which has itself as the type of the instance, and protocols can't have bonafide instances themselves.
If you think carefully about it, it is impossible to well-define what you are trying to do here. Suppose we had the protocol
protocol JSONModel {
init(json: JSON)
}
but then two classes:
class CurrentDownload: JSONModel {
let someProperty: String
required init(json: JSON) {
//Some other code perhaps.
someProperty = json["someProperty"].stringValue
}
}
class FutureDownload: JSONModel {
let differentProperty: String
required init(json: JSON) {
//Different code.
differentProperty = json["differentProperty"].stringValue
}
}
whereas before one might argue that
JSONModel.Type(json: JSON)
(this code is equivalent to your code) should compile and run because we have given an implementation of init, we now can't deny that there is confusion - which implementation should we use here?? It can't choose one, and most would argue that it shouldn't try, and so it doesn't.
What you need to do is initialise with some class.
If you are looking for a minimal class that adheres to JSONModel and no more, you'll need to write such a class e.g.
class BasicJSONModel: JSONModel {
let someProperty: String
required init(json: JSON) {
//Some other code perhaps.
someProperty = json["someProperty"].stringValue
}
}
Then do
private let modelClass: BasicJSONModel//.Type not needed with a class
let model = modelClass(json: modelJSON)
of course this is probably silly and one may just write
let model = BasicJSONModel(json: modelJSON)
Or you could just write a common superclass if the protocol's only use is for this:
class SuperJSONModel {
let someProperty: String//This is not needed of course and you could just strip down to the init only.
init(json: JSON) {
//Some other code perhaps.
someProperty = json["someProperty"].stringValue
}
}
and then is you wanted to check that some object is "conforming" to the what was the JSONModel, you simply check that it is a subclass of SuperJSONModel.

Resources