Swift error when a method has not been called previously - swift

Hi I would like to ask if it is any way to get an error on xCode at compiling, when you are using a class method that needs to call first to another method?
I explain:
class MyClass {
func initializeClass(){
}
func loadConfig() {
}
}
var myClass = MyClass()
myClass.loadConfig() --> Throw Error while coding, the same as you get when you don't implement a required protocol function
Correct way :
myClass.initializeClass().loadConfig()

One way to approach this situation is by using the Proxy Design Pattern. Rather than adding both methods to MyClass, make loadConfig() an instance method of MyClassInitProxy:
public class MyClass {
public class MyClassInitProxy {
let owner:MyClass
public func loadConfig() {
// Do the config work using owner to access MyClass
}
private init(owner:MyClass) {
self.owner = owner
}
}
public func initializeClass() -> MyClassInitProxy {
// Do preparation, then
return MyClassInitProxy(owner:self)
}
}
Now the only way one could call loadConfig is by obtaining MyClassInitProxy through initializeClass() call:
var myClass = MyClass()
myClass.initializeClass().loadConfig()

The short answer is - No, you can't have a compile-time error using this approach.
However if you want to make it impossible for anyone to instantiate your class without having configuration prepared, then just require the configuration as an argument in the initializer. E.g.
class MyClass {
init(config: YourConfigType) {
// do something with the config parameter
}
}
... read config from somewhere and create config variable ...
let x = MyClass(config: config)
And then you have a "compile time error" whenever someone wants to use your class without having config setup initially.

Related

How to implement custom implementation of method?

I'm drawing a blank for some reason.. If I want to make a bunch of objects from a class, but I want each instance to have its own unique implementation of a certain method, how would I do this?
For example:
class MyClass {
var name: String
func doSomething() {
// Each object would have custom implementation of this method, here.
}
}
Do I provide each object with its own closure during initialization, and then call that closure in the doSomething() method? I'm trying to figure out the correct or "Swiftly" way to do this. I'm also thinking along the lines of something with protocols, but I can't seem to figure out how to go about this.
I think there're many ways to do it.
In case of Base class + some sub-classes (e.g. Animal, subclassed by Dog, Cat, etc), you can do this:
First of all it's a good idea to define a protocol:
protocol MyProtocol {
func doSomething()
}
Also provide a default implementation, which throws a fatal error if a class doesn't override that method:
extension MyProtocol {
func doSomething() {
fatalError("You must override me")
}
}
Now your base class confirms the protocol thanks to default implementation. But it will throw a fatal error at runtime:
class MyClass: MyProtocol {
// conformant
}
Child class, however, will run correctly as long as it overrides this function:
class MyOtherClass: MyClass {
func doSomething() {
print("Doing it!")
}
}
You could also move fatal error into base class, and not do any extension implementation.
In case of many instances of the same Class, that solution makes no sense. You can use a very simple callback design:
typealias MyDelegate = () -> Void
class MyClass {
var delegate: MyDelegate?
func doSomething() {
delegate?()
}
}
let x = MyClass()
x.delegate = {
print("do it!")
}
x.doSomething()
// Or you can use a defined function
func doIt() {
print("also doing it")
}
x.delegate = doIt
x.doSomething()
It can also be that you re looking for Strategy pattern, or Template pattern. Depends on your usage details.
Do I provide each object with its own closure during initialization, and then call that closure in the doSomething() method
Yes. That is extremely common and eminently Swifty. Incredibly miminalistic example:
struct S {
let f:()->()
func doYourThing() { f() }
}
let s = S { print("hello") }
let s2 = S { print("goodbye" )}
s.doYourThing() // hello
s2.doYourThing() // goodbye
Giving an object a settable method instance property is very, very easy and common. It doesn't have to be provided during initialization — you might set this property later on, and a lot of built-in objects work that way too.
That, after all, is all you're doing when you create a data task with dataTask(with:completionHandler:). You are creating a data task and handing it a function which it stores, and which it will call when it has performed the actual networking.

Shared instance accross inheritage

Say a framework provides customizable services through an open class A, that exposes a shared instance to use as follows:
open class A {
public static let shared = A()
open func aService() {}
}
The regular usage of the service is as follows:
A.shared.aService()
Important note: the shared instance itself is also used from within the class A code or related code in the Framework.
Say you want to customize the service through inheritance, and you still want to keep the use of the shared instanced as follows:
override class B: A {
public override func aService() {
super.aService()
}
}
When you refer to the shared instance, unfortunately, it refers to the class A instance where you would like it refers to the inherited class instance.
B.shared.aService() // Failed!: This actually calls A.shared.aService()
One way to fix it is to make the construct as follows:
class A {
public static var shared = A()
}
Then you are sure before any use of the service within you app, to change the instance as follows:
A.shared = B()
B.shared.aService() // OK! This actually calls B.aService()
Though the whole thing works, I would like to make it automatic and not rely on the initial line that changes the shared instance.
How would you do that?
[CODE FOR PLAYGROUND] that illustrates the goal to achieve and to help you better understand the question
open class A {
public static var shared = A()
open func aService() {
print("\(type(of: self)): service (from A)")
}
}
class B: A {
public override func aService() {
super.aService()
print("\(type(of: self)): service (from B)")
}
}
A.shared = B() // Question : How to remove the need to this line, yet achieving the same functionality (and output)
A.shared.aService()
B.shared.aService()
// The output (which is correct) :
//B: service (from A)
//B: service (from B)
//B: service (from A)
//B: service (from B)
There's a solution, but...
I do, personally, agree with the other comments here. This really doesn't sound like a job for the singleton pattern.
In your current solution, you seem perfectly happy to overwrite the singleton instance mid-execution, which means it's not a singleton. There's only ever supposed to be one instance of a singleton, and if you can continually create and assign a new instance to the shared variable without breaking anything, then it's just not necessary to have this global state across your application.
However, for the record, you can achieve what you want with a struct that composes the static instances of each class, and which can detect the calling context and return the appropriate one each time shared is accessed:
protocol ExampleProtocol {
static var shared: ExampleProtocol { get }
func service()
}
struct ExampleProvider {
private static var a = A()
private static var b = B()
static func instance(type: ExampleProtocol.Type) -> ExampleProtocol {
return type == A.self ? ExampleProvider.a : ExampleProvider.b
}
}
class A: ExampleProtocol {
static var shared: ExampleProtocol {
return ExampleProvider.instance(type: Self.self)
}
func service() {
print("Hello")
}
}
class B: A {
override func service() {
print("Goodbye")
}
}
A.shared.service() // Hello
B.shared.service() // Goodbye
So, yes, you can achieve what you want. But there's a pretty strong case for saying that you shouldn't...

Instantiate class from protocol type

I am writing method which takes a type which conforms to a protocol and instantiates an instance of this class. When I build it, the compiler crashes with a segfault. I appreciate that this points to a compiler bug 99% of the time, but I am interested to see if what I'm trying to do is logically correct or am I just throwing absolute nonsense at the compiler and I shouldn't be surprised to see it crash.
Here is my code
protocol CreatableClass {
init()
}
class ExampleClass : CreatableClass {
required init() {
}
}
class ClassCreator {
class func createClass(classType: CreatableClass.Type) -> CreatableClass {
return classType()
}
}
ClassCreator.createClass(ExampleClass.self)
I also tried to rule out passing a Type as a method parameter as being the root of the problem and the following code also crashes the compiler:
protocol CreatableClass {
init()
}
class ExampleClass : CreatableClass {
required init() {
}
}
let classType: CreatableClass.Type = CreatableClass.self
let instance = classType()
So - is this just a straightforward compiler bug and does what I am trying to do seem reasonable, or is there something in my implementation that is wrong?
Edit:
This can be achieved using generics as shown #Antonio below but unfortunately i believe that isn't useful for my application.
The actual non-dumbed down use-case for doing this is something like
protocol CreatableClass {}
protocol AnotherProtocol: class {}
class ClassCreator {
let dictionary: [String : CreatableClass]
func addHandlerForType(type: AnotherProtocol.Type, handler: CreatableClass.Type) {
let className: String = aMethodThatGetsClassNameAsAString(type)
dictionary[className] = handler()
}
required init() {}
}
I usually do that by defining a generic method. Try this:
class func createClass<T: CreatableClass>(classType: T.Type) -> CreatableClass {
return classType()
}
Update
A possible workaround is to pass a closure creating a class instance, rather than passing its type:
class ClassCreator {
class func createClass(instantiator: () -> CreatableClass) -> (CreatableClass, CreatableClass.Type) {
let instance = instantiator()
let classType = instance.dynamicType
return (instance, classType)
}
}
let ret = ClassCreator.createClass { ExampleClass() }
The advantage in this case is that you can store the closure in a dictionary for example, and create more instances on demand by just knowing the key (which is something in 1:1 relationship with the class name).
I used that method in a tiny dependency injection framework I developed months ago, which I realized it works only for #objc-compatible classes only though, making it not usable for my needs...

Swift: overriding an initializer that takes an NSInvocation

I'm trying to create a reusable test harness in Swift with the idea that subclasses will extend the test harness to provide the instance under test, and can add their own subclass-specific test methods, something like this:
class FooTestHarness: XCTestCase {
let instance: Foo
init(instance: Foo) {
self.instance = instance
}
func testFooBehavior() {
XCTAssert(instance.doesFoo())
}
}
class FooPrime: Foo {
func doesFooPrime(): Bool { /* ... */ }
}
class FooPrimeTests: XCTestCase {
init() {
super.init(FooPrime())
}
func myInstance(): FooPrime {
return instance as FooPrime
}
func testFooPrimeBehavior() {
XCTAssert(myInstance().doesFooPrime())
}
}
However, when XCode's testrunner tries to run FooPrimeTests, it doesn't call the no-arg init(), it calls init(invocation: NSInvocation!) (and fails because there isn't one). I tried to override this in FooTestHarness:
init(invocation: NSInvocation!, instance: Foo) {
self.instance = instance
super.init(invocation)
}
and in FooPrimeTests:
init(invocation: NSInvocation!) {
super.init(invocation, FooPrime())
}
but this fails with the message 'NSInvocation' is unavailable.
Is there a workaround?
I'm not os sure if I got it right, but checking the code you suggested you should get a compiler Error like:
Which actually I reckon is quite normal since your FooPrimeTests is just subclassing XCTestCase which has got different init like:
init!(invocation: NSInvocation!)
init!(selector: Selector)
init()
Probably when you posted you're question you're running on an older version of Swift, (I'm currently running it on the Xcode Beta 6.2) that's why you can't see the error. But, and I say again if I got your point right, your class FooPrimeTests can't see you custom initializer just because is sublcassing XCTestCase, rather then FooTestHarness. Which is the class where the init(instance: Foo) is defined.
So you might probably want to define FooPrimeTests as subclass of FooTestHarness. That way you should be able to correctly see your initializer. Hope this help.

How to call instance method inside class using Swift

I am having an issue with calling an instance method within the class itself. If someone can provide me some insight it would be greatly appreciated.
My current code looks like this:
class Rect
{
func printthis() -> String {
return "this is working or what"
}
var toPrint:String = self.printthis()
}
The error I am getting in Xcode is: Use of unresolved identifier 'self'.
What am I missing here?
You can't call an instance method without an instance. The class is merely the template for instances. So i don't what you are trying to do here...
But the answer is no, you cannot call an instance method form the class definition because there is no instance yet.
Perhaps you want to delcare a class method and use that to set an instance variable on creation? If so, you might do that like this:
class Rect {
class func printthis() -> String {
return "this is working or what"
}
var toPrint:String
init() {
toPrint = Rect.printthis()
}
}
var r = Rect()
println(r.toPrint) //-> this is working or what
An instance of a class is not initialized and able to be referenced (even as 'self') until all of its variables have been assigned values.
An option that may work for you is to declare your variable as an implicitly-unwrapped optional, which is assigned nil by default. Then in the class's init method, since all of the variables have been assigned values, you are able to start calling methods on your instance.
class Rect {
var toPrint: String!
init() {
toPrint = printthis()
}
printthis() -> String {
return "this will work"
}
}
the problem is that swift is strict about initing all properties.
you may as a workaround
class Rect
{
func printthis() -> String {
return "this is working or what"
}
var toPrint:String = ""
init() {
toPrint = printthis()
}
}