Swift extension for selected class instance - swift

In Objective-C category, you can bring in the extended capability introduced by the category methods by including the header of the category in your class.
It seems like all Swift extensions are automatically introduced without import. How do you achieve the same thing in Swift?
For example:
extension UIView {
// only want certain UIView to have this, not all
// similar to Objective-C, where imported category header
// will grant the capability to the class
func extraCapability() {
}
}

Define a protocol that will serve as a selection, wether the extensions should be available or not:
protocol UIViewExtensions { }
then define an extension for the protocol, but only for subclasses of UIView (the other way around won't work):
extension UIViewExtensions where Self: UIView {
func testFunc() -> String { return String(tag) }
}
A class that is defined to have the protocol will also have the extension:
class A: UIView, UIViewExtensions { }
A().testFunc() //has the extension
And if it is not defined to have the protocol, it will also not have the extension:
class B: UIView {}
B().testFunc() //execution failed: MyPlayground.playground:17:1: error: value of type 'B' has no member 'testFunc'
UPDATE
Since protocol extensions don't do class polymorphism, if you need to override functions, the only thing I can think of is to subclass:
class UIViewWithExtensions: UIView {
override func canBecomeFocused() -> Bool { return true }
}
UIViewWithExtensions().canBecomeFocused() // returns true
this could also be combined with the extension, but I don't think it would still make much sense anymore.

You can make extensions private for a particular class by adding private before the extension like so
private extension UIView {
func extraCapability() {
}
}
This will mean it can only be used in that particular class. But you will need to add this to each class that requires this extension. As far as I know there is no way to import the extension like you can in Obj-c

NOTE
Private access in Swift differs from private access in most other languages, as it’s scoped to the enclosing source file rather than to the enclosing declaration. This means that a type can access any private entities that are defined in the same source file as itself, but an extension cannot access that type’s private members if it’s defined in a separate source file.
According to Apple, here, it does not appear you can make extensions private in separate files.
You can create a private extension in the same source file.

Related

Private qualifier to an extension produces fileprivate behavior

Person.swift
class Person {
var name: String
init(name: String){
self.name = name
}
func greet() {
print("Hello, I am \(name)")
}
}
Workplace.swift
class WorkPlace {
var employees: [Person]
init(employees: [Person]) {
self.employees = employees
}
func greet() {
for employee in employees {
employee.customGreeting()
}
}
}
private extension Person {
func customGreeting() {
print("Hi")
}
}
Here I have a simple class called Person defined in Person.swift and a Workplace class defined in Workplace.swift.
The following is an excerpt taken from the Swift language guide (Access Control)
Alternatively, you can mark an extension with an explicit access-level modifier (for example, private) to set a new default access level for all members defined within the extension.
According to this I would expect the method customGreeting in the private extension of Place not be visible inside Person.swift as it would be a private method and it is defined in a different file than the one the class is declared in, which is exactly what happens. I would also expect that method to not be visible inside Workplace.swift but it does. I am able to compile this code without any errors.
If I mark the method as private explicitly then it is not visible inside Workplace.swift. Shouldn't specifying the extension as private be enough to make the method private like it says in the language guide?
private extension Person {
private func customGreeting() {
print("Hi")
}
}
I know that this is a contrived example and I am just trying to get a clear picture of how access control works in swift.
The issue isn't that methods declared in a private extension available in other classes, but rather, more narrowly, that private qualifier to an extension produces fileprivate behavior.
This is explicitly acknowledged in SE-0025, which says:
As before, an extension with an explicit access modifier overrides the default internal access by specifying a default scope. Therefore, within an extension marked private, the default access level is fileprivate (since extensions are always declared at file scope). This matches the behavior of types declared private at file scope.
This seems inconsistent with their broader statement:
... you can mark an extension with an explicit access-level modifier (for example, private) to set a new default access level for all members defined within the extension. This new default can still be overridden within the extension for individual type members.
While there is an inconsistency here, it would appear to be a conscious decision.

Swift protocol to only implemented by specific classes

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.

Can a Swift class be extended multiple times with the same methods?

I am designing a framework that uses protocols and extensions to allow for third-parties to add support for my framework to their existing classes.
I'd also like to include some built-in extensions for known classes like UIView, but I don't want to prevent users from defining their own additional support for the same classes.
My question is is there any way that I can extend the same class twice, and override the same (protocol) method in that class both times, while still having some way to call the other if the first one fails.
Elaboration: I really have three goals here I want to achieve:
I want to allow users of my framework to provide their own extensions for their own (or any) UIView subclasses.
I also need some way to allow general behavior that can apply to all UIViews as a fallback option (i.e. if the specific class extension can't handle it, fall back on the generic UIView extension).
I'd also like to separate out my own implementation, by providing some built-in generic view handling, but in such a way that it doesn't prevent third parties from also defining their own additional generic handling. (If I can't do this, it's not a big deal, the first two parts are the most important.)
I have part 1 working already. The problem is how to get this fallback behavior implemented. If I do it all with extensions, the subclass will override the superclass's implementation of the protocol method. It could call super.method, but I'd like to avoid putting that responsibility on the subclass (in case the author forgets to call super).
I'd like to do this all from the framework code: first, call the object's protocol method. If it returns false, I'd like to somehow call the generic UIView handler.
Now that I'm typing it all out, I'm wondering if I can just use a different method for the generic fallback and be done with it. I just figured it would be elegant if I could do it all with one method.
No! It can't be extended multiple times.
extension Int {
var add: Int {return self + 100} // Line A
}
extension Int {
var add: Int {return self + 105} //Line B
}
Doing so would create a compile time error ( on Line B) indicating: Invalid redeclaration of 'add'
Swift is a static typing language and helps you find these sorts of errors before runtime
In Objective-C you can write this and still not get an error, however the result would be undefined, because you wouldn't know which method gets loaded first during runtime.
Overriding a single protocol method twice in 2 separate extensions wouldn't work, because the protocol method names would collide. Once compiled, they're all just methods on the same class. With that in mind, perhaps put all the protocol methods in their own extension & call them from within the other ones?
The following could be one general option. Could get messy if you decide to keep adding additional extension functionality.
class baseClass {
//stuff
}
extension baseClass: myProtocol {
override func myProtocolMethod(args) -> returnType {
//Repeat this in a separate extension & your method names collide
var status: Bool
//protocol method code sets status as appropriate...
return status = true ? optOne(status) : optTwo(status)
}
func optOne(status:Bool) -> returnType{
//do the 'true' thing
return returnType
}
func optTwo(status:Bool) -> returnType{
//do the 'false' thing
return returnType
}
}
extension baseClass {
var oneExtension = myProtocolMethod(someArg)
}
extension baseClass {
var twoExtension = myProtocolMethod(someArg)
}
I realize this Question is over a year old and the original poster has probably moved on to other things, but I'd like to share an idea anyways and perhaps get some feedback.
You say that you want a method that can be overwritten multiple times. The short answer, like many in this thread have given is no, but the long answer is yes.
We can solve the issue with a bit of generic magic.
class MyView: UIView {
var customizer: MyProtocol<MyView> = Defaults()
func willCallCustomizer() {
customizer.coolMethod(self)
}
}
// Use this class as if it were a protocol
class MyProtocol<T: UIView>: NSObject {
func coolMethod(_ view: T) {}
}
// Class inherits from the "protocol"
class Defaults: MyProtocol<MyView> {
override func coolMethod(_ view: MyView) {
// Some default behavior
}
}
/// on the clients end...
class CustomerCustomizer: MyProtocol<MyView> {
override func coolMethod(_ view: MyView) {
// customized behavior
}
}
So if the client wants to use their own customizer they can just set it, otherwise it will just use the default one.
myViewInstance.customizer = CustomerCustomizer()
The benefit of this approach is that the client can change the customizer object as many times as they want. Because MyProtocol is generic, it may be used for other UIView's as well; thus fulfilling the role of a protocol.

A way to inherit from multiple classes

I have two classes I want to use in my new class. The first one implements a swipe to delete and the second enables a long press gesture:
class DeleteItem: UITableViewCell {
}
class OpenDetail: UITableViewCell {
}
Since Swift doesn't allow a class to inherit from multiple classes the following example obviously won't work:
class ItemViewCell: DeleteItem, OpenDetail {
}
So in order to create ItemViewCell and having both options, I'll have to have one of the classes to inherit from each other:
class DeleteItem: UITableViewCell {
}
class OpenDetail: DeleteItem {
}
class ItemViewCell: OpenDetail {
}
The problem is, if I only want the long press gesture I'll have to create a new class without inheriting from DeleteItem. Is there a better way of doing this?
This is the perfect case for using Protocols and Protocol extension. A swift protocol is like an interface in Java for example. A protocol can define a set of functions which has to be implemented by the entities which want to conform to this protocol, moreover a protocol can define properties which has to be present in these entities too. For example:
protocol ItemDeleter {
var deletedCount: Int {get set}
func deleteItem(item: ItemType)
}
The problem is, that each entity would have to provide its own implementation of func deleteItem(item: ItemType) even if multiple entities share the same logic of deleting an item, this where a protocol extension comes in handy. For example:
extension ItemDeleter {
func deleteItem(item: ItemType) {
// logic needed to delete an item
// maybe incremented deletedCount too
deletedCount++
}
}
Then you could make your ItemViewCell conform to the ItemDeleter protocol, in this case all you need is to make sure that ItemViewCell has a property deletedCount: Int. It does not need to provide an implementation for func deleteItem(item: ItemType) as the protocol itself provides a default implementation for this function, however you can override it in your class, and the new implementation will be used. The same applies for DetailOpener protocol.

How do I store data submitted to computed properties in a protocol extension?

In the app that I'm currently working on, I try to take advantage of the new protocol extension feature in Swift. The idea is that I have a lot of classes implementing the same protocol. Since all these classes should have the same computed properties, and since the properties should behave identically in de different classes, I thought it would be nice to add the functionality only once.
My code is structured as the following example
protocol SomeProtocol { ... }
// There could potentially be unlimited different versions of "SomeClass" that implements "SomeProtocol"
class SomeClass : SomeProtocol { ... }
extension SomeProtocol {
var computedProperty1: Type? {
get { getData(SOME_ENUM) }
set { validateAndSave(newValue, atKey: SOME_ENUM) }
}
var computedProperty2: Type? {
get { getData(SOME_OTHER_ENUM) }
set { validateAndSave(newValue, atKey: SOME_OTEHR_ENUM) }
}
...
func getData(atKey: ENUM_TYPE) -> Type? {
[NEED SOME WAY TO GET THE SAVED DATA AND RETURN IT]
}
func validateAndSave(value: Type?, atKey: ENUM_TYPE) {
[NEED SOME WAY TO SAVE DATA FOR LATER RETURNING]
}
}
// The properties needs to be visible to the client code like this:
class ClientCode {
let someClassObject: SomeProtocol = SomeClass()
someClassObject.computedProperty1 = Type()
print(someClassObject.computedProperty1)
}
(The code above shows signs of storing the data in different dictionaries, which was my first thought)
The problem is that an extension does not support stored properties. But where/how do I store the data submitted to the computed properties then?
I can think of 2 different solutions, but none of them good..
I could transform the extension into a class that implements SomeProtocol instead, and then make SomeClass a subclass of it. That would allow me to save the data in stored properties. But it would also require me to implement all the methods the protocol requires in the new class - and that makes absolutely no sense, since it's the different versions of SomeClass that should provide different functionality..
I could just drop the entire extension idea, and move all the properties into SomeProtocol. But that would require me to implement all the computed properties in all the different versions of SomeClass with identical functionality, and the whole point of my extension idea was to avoid writing the same implementation for the same properties over and over again..
Is there some completely easy logical solution that I have overlooked?
... or a nice way to save data in a protocol extension that I do not know about?
... or another way of obtaining the desired functionality?
... or should I just suck it up and use one of my not-so-pretty solutions?
Assuming I understand the question correctly to work around the fact that protocol extensions don't support stored properties you could extend NSObject and use the objective C runtime to store your properties.
import ObjectiveC
private var AssociationKey: UInt8 = 0
class YourStoredObject {
// Whatever object your are persisting
}
extension NSObject {
var yourStoredObject: (YourStoredObject)! {
get {
return objc_getAssociatedObject(self, &AssociationKey) as? YourStoredObject
}
set(newValue) {
objc_setAssociatedObject(self, &AssociationKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
}
}
}
protocol YourProtocol {
var yourStoredObject: YourStoredObject! { get set }
}
extension YourProtocol {
func customYourStoredObjectGetter() -> YourStoredObject {
return yourStoredObject
}
}
extension UILabel : YourProtocol {
func myExtendedFunc() {
// Get (and print) your object directly
print(yourStoredObject)
// Get your object through a protocol custom getter
print(customYourStoredObjectGetter())
// Set your object
yourStoredObject = YourStoredObject()
}
}
I'm not saying this is the best solution but this is the only solution I can think of. I'm also looking for nicer Swift alternatives but still have not found any.
Protocol extension? Why?
Sometimes we get so hung up on an idea that we ignore a practical solution staring right at our face.
1. Do you have set of computed properties? No, you want stored properties.
Since all these classes should have the same computed properties, and
since the properties should behave identically in de different
classes...
... but later
The problem is that an extension does not support stored properties.
But where/how do I store the data submitted to the computed properties
then?
2. Assuming that it is a set of stored properties that you want, you practically provided the solution yourself! Made one change that will make sense now.
I could transform the extension into a class that implements
SomeProtocol instead, and then make SomeClass a subclass of it. That
would allow me to save the data in stored properties.
You extend the class whenever you want to and then confirm its subclasses to SomeProtocol to get the features. This is cleaner.
On a side note, Swift's protocols not being able to store properties is by design. Protocols do not have existence in their own right and it doesn't make sense to add stored properties in them.