I'm trying to extend the functionality of a existing type in Swift. I want to use dot syntax to call the methods on the type.
I want to say:
existingType.example.someMethod()
existingType.example.anotherMethod()
I'm currently using an extension like so:
extension ExistingType {
func someMethod() {
}
func anotherMethod() {
}
}
existingType.someMethod()
existingType.anotherMethod()
Doing this will expose too many functions. So, I want to write these methods in a class, and just extend the ExistingType to use an instance of the class. I'm not sure the right way to go about this.
if I were actually implementing the existing type, I would do the following:
struct ExistingType {
var example = Example()
}
struct Example {
func someMethod() {
}
func anotherMethod() {
}
}
Allowing me to call the methods by:
let existingType = ExistingType()
existingType.example.someMethod()
The issue is I'm not implementing the type, because it already exists. I just need to extend it.
It looks like you are trying to add another property example the existing class ExistingType and call methods of that property. You cannot add properties in extensions, though. The only way to add another property to the existing class is to subclass it.
You can create a new struct.
struct NewType {
let existingType: ExistingType
func someMethod() {
}
func anotherMethod() {
}
}
Related
So I have a protocol setup in swift, and I'd like to add additional information in the methods (like comments) to the classes that use it
Currently its created using
protocol ImportProtocol {
var moc : NSManagedObjectContext { get set }
init(viewContext: NSManagedObjectContext)
// Various methods which aren't an issue
func importDIM()
}
extension ImportProtocol {
// Default implementation of the various methods above
// No implementation of init or importDIM methods
}
Is it possible to make it to that when it adds the importDIM methods it provides some content on the method to begin with? Currently the method is blank but I'd like to make it add with
func importDIM() {
let dim = addDIM()
// Stage 1
}
If you want to achieve this, you have to define a protocol with your methods, and an protocol extension where you can set computed vars and methods with code.
Example :
protocol ImportProtocol {
}
extension ImportProtocol {
func importDIM() {
let dim = addDIM()
// Stage 1
}
}
And then your classes that implements the protocol have also the base methods with code.
Some more documentation about that with more example :
https://cocoacasts.com/how-to-create-an-abstract-class-in-swift
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.
I'm trying to check the class of an instance which conforms to a protocol.
I have a protocol.
protocol ToolbarProtocol {
func show()
func hide()
}
I have a class which conforms to that protocol.
class GameToolbar: ToolbarProtocol {
...
}
I have a manager class I createed to manage my toolbars.
class ToolbarManager {
var existingToolbars: [Game.rotation: Array<ToolbarProtocol>]
}
In this manager, I have a function that wants to find the first instance of a specific type of toolbar.
func getDebugToolbar() -> ToolbarProtocol? {
return existingToolbars[.east]?.first(where: { (toolbar: ToolbarProtocol) -> Bool in
toolbar.isKind(of: GameToolbar.self) //This line causes an error because .isKind is not a member of ToolbarProtocol
})
}
I can't call isKind(of) on toolbar, which previously worked when my toolbars were a different kind of class provided by an external library (which I'm trying to remove from my codebase because I want different functionality).
I tried making my protocol extend AnyObject, but I think that's implicit anyway, and it had no effect.
How can I check an array of instances which conform to a given protocl, to check for specific class types?
I think you would need to attempt to cast it, like
if let vc = toolbar as? GameToolbar {}
In your case, you might need something like this:
func getDebugToolbar() -> ToolbarProtocol? {
return existingToolbars[.east]?.first(where: { (toolbar: ToolbarProtocol) -> Bool in
let _ = toolbar as? GameToolbar
})
}
I have a Swift protocol defined as follows:
protocol SmartContract {
func apply(transaction :Transaction)
func addBrokenRule(_ brokenRule: BrokenRule)
var brokenRules :[BrokenRule] { get set }
}
I have an extension on SmartContract defined as follows:
extension SmartContract {
mutating func addBrokenRule(_ brokenRule :BrokenRule) {
if self.brokenRules == nil {
self.brokenRules = [BrokenRule]()
}
self.brokenRules.append(brokenRule)
}
}
I also have a class MoneyTransferContract which conforms to the protocol but does not define brokenRules. This is because I have defined the brokenRules inside the extension.
class MoneyTransferContract : SmartContract {
func apply(transaction :Transaction) { // do something here }
}
My question is how can I make sure that MoneyTransformContract conforms to the SmartContract protocol. Is there anyway to have BrokenRule available to MoneyTransformContract without defining it again and again in different SmartContracts.
john doe wrote:
Is there anyway to have BrokenRule available to MoneyTransformContract without defining it again and again in different SmartContracts.
What you want is a superclass/subclass relationship for that behavior.
class SmartContract {
func apply(transaction :Transaction) {
//implemention
}
var brokenRules: [BrokenRule] = []
func addBrokenRule(_ brokenRule :BrokenRule) {
brokenRules.append(brokenRule)
}
}
class MoneyTransferContract : SmartContract {
// Gets `brokenRules` for free from superclass.
}
class BitCoinTransferContract : SmartContract {
// Gets `brokenRules` for free from superclass.
}
If I'm understanding correctly, there is no way to do what you want. (EDIT: as Jeff notes, if you want to use inheritance as opposed to a protocol, this is possible. See his answer for how). Protocols in Swift are just lists of requirements that it is up to implementing types to properly define. Protocols generally don't have any say over the actual behavior or implementation of implementing types, and only guarantees that the properties and functions exist. Your SmartContract protocol says that every SmartContract must have a function apply(transaction:), a function addBrokenRule(_:), and a property brokenRules which can be accessed and modified.
When a type implements SmartContract it has to define each one of these. Just as you have to write out the signature to tell the compiler that you are implementing apply(transaction:), you also have to tell the compiler how the property brokenRules will be implemented. You could obtain this functionality in a somewhat useless way, by defining an extension which has brokenRules as a computed property which is essentially a no-op:
extension SmartContract {
var brokenRules: [BrokenRule] {
get { return [] }
set(newRules) { }
}
}
But this means that any implementing type which forgets to specify their own implementation for brokenRules will have a brokenRules property which always resolves to an empty array.
One reason for this is Swift's computed properties. For some implementing type, it might not make sense for brokenRules to be stored as an array--and a protocol can't force that. That's an implementation detail that a protocol author can't (and shouldn't) worry about. For instance, if BrokenRules were easily convertible to and from strings, you could imagine some class which implemented SmartContract like so:
class StringContract: SmartContract {
var ruleString: String
var brokenRules: [BrokenRule] {
get {
let stringArray = ruleString.split(separator: ",")
return stringArray.map { BrokenRule(string:String($0)) }
}
set(newRules) {
let stringArray = newRules.map { $0.stringValue }
ruleString = stringArray.joined(separator: ",")
}
}
func apply(transaction: Transaction) {
// do something here...
}
init() {
ruleString = ""
}
}
Note that we don't have to specify an implementation for addBrokenRule(_:). That's what your protocol extension gets you. By providing an implementation in the extension, you ensure that all implementing types have a default implementation of the function, and so they can choose to forego defining their own.
I want to create a protocol which is only adopted by a specific class and its subClassses in swift.
I know i can use protocol extensions like this
protocol PeopleProtocol: class {
}
extension PeopleProtocol where Self: People {
}
But the method that will go in my protocol will be an init method which will be implemented by a class or its subClasess and will return only some specific type of objects.
some thing like this.
protocol PeopleProtocol: class {
init() -> People
}
or i can do some thing like this
extension PeopleProtocol where Self : People {
init()
}
But there are two problems,
In the first approach if i put an init method in the protocol it don't allow me to put a return statement there like -> People in the first approach.
In the second approach i have to provide a function body in the protocol extensions, so this thing will be out of question, as i don't know what specific type to return for this general implementation.
So any suggestions how i can call an init method and do either:
Let the protocol (not protocol extension) to be implemented by only specific classe and its subClasses.
Or return an instance of a certain from protocol extension method without giving its body.
You could add a required method that you only extend for the appropriate classes.
for example:
protocol PeopleProtocol
{
var conformsToPeopleProtocol:Bool { get }
}
extension PeopleProtocol where Self:People
{
var conformsToPeopleProtocol:Bool {return true}
}
class People
{}
class Neighbours:People
{}
extension Neighbours:PeopleProtocol // this works
{}
class Doctors:People,PeopleProtocol // this also works
{}
class Dogs:PeopleProtocol // this will not compile
{}
This could easily be circumvented by a programmer who would want to, but at least it will let the compiler warn you if you try to apply the protocol to other classes.