This is probably 2 swift questions in one...
How do I solve a situation where I want to extend an existing base class (UIView in my case) with functionality that requires stored properties? ...so that I can reuse the code for other classes?
I have tried to solve it through composition below, but I don't know if there is a more obvious way that I just can't see as I am fairly new to swift...
The second question:
In my implementation I have an abstract class ManagedComponentImpl which needs an eventReceiver object which is going to be the containing UIView subclass.
The problem I have with my implementation is that swift forces me to define an object binding where Receiver:NSObject for ManagedComponentImpl, so that I can declare the optional variable eventReceiver as weak. (and I guess I would create a memory leak otherwise). However I would want to use this implementation on a variety of objects (which could of course all inherit NSObject, but they do not actually need to for other reasons but this, so it seems odd). So question number 2: Is there a way to avoid this?
EDIT: And yes! I made a mistake mixing model and view code here, but I guess the fundamental problem remains when you switch UIViewController for UIView :-)
public protocol ManagedConnection {
var connectionKey:String { get set }
}
public protocol ManagedComponent: ConnectionObserver {
var connectionKey:String { get set }
func connectTo()
func disconnectFrom()
}
public protocol EventReceiver: ConnectionObserver {
var variableSet:Set<VariableID>? { get }
var handleVariableUpdates: ((Set<VariableID>)->Void)? { get }
}
class ManagedComponentImpl<Receiver: EventReceiver> where Receiver:NSObject {
public var _connectionKey: String = Shared
//The connection Key
public var connectionKey: String
{
set {
disconnectFrom()
self._connectionKey = newValue
connectTo()
}
get {
return _connectionKey
}
}
// The varset needed by this control
weak var eventReceiver:Receiver!
// handler for the status pane variables
//
var connectionObserverHandlerID:UInt16 = 0
var eventHandlerID:UInt16 = 0
public init(receiver:Receiver) {
self.eventReceiver = receiver
}
public func connectTo() {
guard let manager = Connections.shared[self.connectionKey] else { return }
let connection = manager.connection
// disconnect any previous connections
disconnectFrom()
// Connect the connection observer
connectionObserverHandlerID = connection.addConnectionObserver(observer: eventReceiver)
if let variableSet = eventReceiver.variableSet, let handler = eventReceiver.handleVariableUpdates {
eventHandlerID = connection.requestVariables(variables: variableSet, handler: handler)
}
}
public func disconnectFrom(){
guard let manager = Connections.shared[self.connectionKey] else { return }
let connection = manager.connection
// Disconnect
if connectionObserverHandlerID != 0 {
connection.removeConnectionObserver(id: connectionObserverHandlerID)
}
if eventHandlerID != 0 {
connection.unRequestVariables(ident: eventHandlerID)
}
}
}
class ManagedUIView: UIView, ManagedComponent, EventReceiver {
private var component:ManagedComponentImpl<ManagedUIView>!
public var variableSet:Set<VariableID>?
public var handleVariableUpdates:((Set<VariableID>)->Void)?
public override init(frame: CGRect) {
super.init(frame: frame)
component = ManagedComponentImpl<ManagedUIView>(receiver: self)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
component = ManagedComponentImpl<ManagedUIView>(receiver: self)
}
var connectionKey:String {
set {
component.connectionKey = newValue
}
get {
return component.connectionKey
}
}
func connectTo() {
component.connectTo()
}
func disconnectFrom() {
component.disconnectFrom()
}
func notifyState(state: ConnectionState) {}
}
Okay - for everybody reading this, the answers are:
- The problem should probably be solved by a delegate and not by inheritance.
- To avoid inheriting from NSObject: the problem seems to be that protocols can not only be implemented by classes. Therefore the protocol needs a class limitation to work as weak references. As a result ManagedComponentImpl does not need to be generic any more and I can just have a weak CAPEvent receiver optional.
Related
I have created an protocol extension of UIImageView and added a bool property isFlipped to the extension. My problem is that if I set isFlipped true of false for one object is sets the same values for the all the UIImageView objects. Can anyone guide how to handle it separately for each UIImageView objects.
protocol FlipImage {
var isFlipped: Bool { get set }
}
var flippedValue = false
extension UIImageView:FlipImage{
var isFlipped: Bool {
get {
return flippedValue
}
set {
flippedValue = newValue
}
}
}
If you want to add stored properties using extensions, here's a little trick I used that allows you to do it for base classes that you can override (namely view controllers, which is the one I used it for):
This protocol allows a base class to be extended with stored properties in extensions and in protocols:
protocol ExtensibleObject:class
{
var extendedProperties:[String:Any] { get set }
}
extension ExtensibleObject
{
func get<T>(_ defaultValue:T, _ file:String = #file, _ line:Int = #line) -> T
{
return (extendedProperties["\(file):\(line)"] as? T) ?? defaultValue
}
func set<T>(_ newValue:T, _ file:String = #file, _ line:Int = #line)
{
return extendedProperties["\(file):\(line)"] = newValue
}
}
To use the protocol, you need to create a subclass of the base class to add storage for all extended properties (for the class and all its sub classes).
class ExtensibleViewController:UIViewController, ExtensibleObject
{
var extendedProperties:[String:Any] = [:]
}
Note that you can do it directly in the base class if it is yours.
You would then use the "extensible" base class for your own subclass instead of the base class:
class MyVC:ExtensibleViewController
{}
From then on, any of the subclass can receive new "stored" properties in extensions:
extension MyVC
{
var newStoredProperty:Int
{ get { return get(0) } set { set(newValue) } } // set and get must be on same line
}
Stored properties can also be added through protocol adoption for classes implementing the ExtensibleObject protocol:
protocol ListManager:ExtensibleObject
{
var listContent:[String] { get set }
}
extension ListManager
{
var listContent:[String]
{ get { return get([]) } set { set(newValue) } }
}
extension MyVC:ListManager {}
Bear in mind that these extended properties behave as lazy variables and that they have some additional overhead when used. For UI components and view controllers, this is usually not a problem.
Let's say I have a class that implements a beautiful subject-observer pattern thus. (This is Swift 3; Swift 2 would be no different in essence.)
protocol Delegate : class
{
func method()
}
class Subject
{
private typealias WeakDelegate = WeakReference< Delegate >
private var nextAvailableDelegateId = 0
private var delegates = [ Int : WeakDelegate ]()
#discardableResult
public func addDelegate( _ delegate: Delegate ) -> Int
{
let id = nextAvailableDelegateId
nextAvailableDelegateId += 1
delegates[ id ] = WeakDelegate( value: delegate )
return id
}
public func removeDelegate( _ idForDelegate: Int )
{
delegates.removeValue( forKey: idForDelegate )
}
fileprivate func eachDelegate( fn: (Delegate) -> Void )
{
for (key, weakDelegate) in delegates
{
// Has this weak delegate reference become nil?
//
guard let delegate = weakDelegate.value else
{
// Yes. Remove it.
delegates.removeValue( forKey: key )
continue
}
fn( delegate )
}
}
private func exampleNotifier()
{
eachDelegate{ $0.method() }
}
}
(I'm taking the idiomatic Swift term "delegate" as roughly equivalent to the design pattern concept "observer".)
The WeakReference type above isn't strictly speaking part of this question, but in case you're curious:
public class WeakReference< T >
{
public var value: T?
{
return abstractValue as? T
}
public init( value: T )
{
abstractValue = value as AnyObject
}
private weak var abstractValue: AnyObject?
}
Now I want to create another class analogous to Subject with another delegate protocol analogous to Delegate. How do I use the implementation I've already written for Subject in the new class?
One answer is to copy and paste the code. Not a good answer.
In C++ we could create a true mixin, a class that contains all the code and data necessary to implement the Subject, templated on a generic Delegate type, and inherit from it wherever we want to make some other class act as a Subject. Quite trivial.
Protocols, protocol extensions, and generics seem to have some of the machinery necessary for this kind of code reuse, but I can't work out how to accomplish it.
Help?
You can use protocol inheritance and generics to derive from some basic protocol.
Each new delegate will inherit from a parent class:
protocol Delegate: class {
func method()
}
protocol DelegateA: Delegate { }
protocol DelegateB: Delegate { }
Your parent subject class can be implemented using a generic conforming to your parent protocol.
class Subject<T: Delegate> {
private typealias WeakDelegate = WeakReference<T>
private var nextAvailableDelegateId = 0
private var delegates = [Int: WeakDelegate]()
#discardableResult
public func addDelegate(_ delegate: T) -> Int {
let id = nextAvailableDelegateId
nextAvailableDelegateId += 1
delegates[id] = WeakDelegate( value: delegate )
return id
}
public func removeDelegate(_ idForDelegate: Int) {
delegates.removeValue(forKey: idForDelegate)
}
fileprivate func eachDelegate( fn: (T) -> Void ) {
for (key, weakDelegate) in delegates {
// Has this weak delegate reference become nil?
guard let delegate = weakDelegate.value else {
// Yes. Remove it.
delegates.removeValue( forKey: key )
continue
}
fn( delegate )
}
}
private func exampleNotifier() {
eachDelegate{ $0.method() }
}
}
Each new subject can be instantiated as a generic conforming to your child delegates.
class SubjectA<T: DelegateA>: Subject<T> { }
class SubjectB<T: DelegateB>: Subject<T> { }
I can not figure out why Xcode playground is crashing, here is my basic setup
protocol Shootable {
func shoot()
}
class BaseMissile: Shootable {
var damage = 0
func shoot() {
println("Pew pew for \(damage) damage")
}
}
class Missile1: BaseMissile {
override init() {
super.init()
damage = 1
}
}
protocol Targetable {
var life: Int {get set}
}
class BaseSpaceship: Targetable {
var life = 0
var currentMissile: BaseMissile!
func printHealth() {
println("My current life: \(life)")
}
}
class Spaceship1: BaseSpaceship {
override init() {
super.init()
life = 1
currentMissile = Missile1()
}
}
var spaceship = Spaceship1()
spaceship.printHealth()
spaceship.currentMissile.shoot()
specifically the last line spaceship.currentMissile.shot() crashes the playground. If I move var currentMissile: BaseMissile! from BaseSpaceship to Spaceship1 it works, but is that an acceptable way to handle this?
I guess this happens because BaseSpaceship class has no initializers and var currentMissile: BaseMissile! cant be nil. So you either should do it optional by replacing ! with ? or give it a default value.
Is there a way to create an abstract class in the Swift Language, or is this a limitation just like Objective-C? I'd like to create a abstract class comparable to what Java defines as an abstract class.
There are no abstract classes in Swift (just like Objective-C). Your best bet is going to be to use a Protocol, which is like a Java Interface.
With Swift 2.0, you can then add method implementations and calculated property implementations using protocol extensions. Your only restrictions are that you can't provide member variables or constants and there is no dynamic dispatch.
An example of this technique would be:
protocol Employee {
var annualSalary: Int {get}
}
extension Employee {
var biweeklySalary: Int {
return self.annualSalary / 26
}
func logSalary() {
print("$\(self.annualSalary) per year or $\(self.biweeklySalary) biweekly")
}
}
struct SoftwareEngineer: Employee {
var annualSalary: Int
func logSalary() {
print("overridden")
}
}
let sarah = SoftwareEngineer(annualSalary: 100000)
sarah.logSalary() // prints: overridden
(sarah as Employee).logSalary() // prints: $100000 per year or $3846 biweekly
Notice that this is providing "abstract class" like features even for structs, but classes can also implement the same protocol.
Also notice that every class or struct that implements the Employee protocol will have to declare the annualSalary property again.
Most importantly, notice that there is no dynamic dispatch. When logSalary is called on the instance that is stored as a SoftwareEngineer it calls the overridden version of the method. When logSalary is called on the instance after it has been cast to an Employee, it calls the original implementation (it doesn't not dynamically dispatch to the overridden version even though the instance is actually a Software Engineer.
For more information, check great WWDC video about that feature: Building Better Apps with Value Types in Swift
Note that this answer is targeted at Swift 2.0 and above
You can achieve the same behaviour with protocols and protocol extensions.
First, you write a protocol that acts as an interface for all the methods that have to be implemented in all types that conform to it.
protocol Drivable {
var speed: Float { get set }
}
Then you can add default behaviour to all types that conform to it
extension Drivable {
func accelerate(by: Float) {
speed += by
}
}
You can now create new types by implementing Drivable.
struct Car: Drivable {
var speed: Float = 0.0
init() {}
}
let c = Car()
c.accelerate(10)
So basically you get:
Compile time checks that guarantee that all Drivables implement speed
You can implement default-behaviour for all types that conform to Drivable (accelerate)
Drivable is guaranteed not to be instantiated since it's just a protocol
This model actually behaves much more like traits, meaning you can conform to multiple protocols and take on default implementations of any of them, whereas with an abstract superclass you're limited to a simple class hierarchy.
I think this is the closest to Java's abstract or C#'s abstract:
class AbstractClass {
private init() {
}
}
Note that, in order for the private modifiers to work, you must define this class in a separate Swift file.
EDIT: Still, this code doesn't allow to declare an abstract method and thus force its implementation.
The simplest way is to use a call to fatalError("Not Implemented") into the abstract method (not variable) on the protocol extension.
protocol MyInterface {
func myMethod() -> String
}
extension MyInterface {
func myMethod() -> String {
fatalError("Not Implemented")
}
}
class MyConcreteClass: MyInterface {
func myMethod() -> String {
return "The output"
}
}
MyConcreteClass().myMethod()
After I struggled for several weeks, I finally realized how to translate a Java/PHP abstract class to Swift:
public class AbstractClass: NSObject {
internal override init(){}
public func getFoodToEat()->String
{
if(self._iAmHungry())
{
return self._myFavoriteFood();
}else{
return "";
}
}
private func _myFavoriteFood()->String
{
return "Sandwich";
}
internal func _iAmHungry()->Bool
{
fatalError(__FUNCTION__ + "Must be overridden");
return false;
}
}
public class ConcreteClass: AbstractClass, IConcreteClass {
private var _hungry: Bool = false;
public override init() {
super.init();
}
public func starve()->Void
{
self._hungry = true;
}
public override func _iAmHungry()->Bool
{
return self._hungry;
}
}
public protocol IConcreteClass
{
func _iAmHungry()->Bool;
}
class ConcreteClassTest: XCTestCase {
func testExample() {
var concreteClass: ConcreteClass = ConcreteClass();
XCTAssertEqual("", concreteClass.getFoodToEat());
concreteClass.starve();
XCTAssertEqual("Sandwich", concreteClass.getFoodToEat());
}
}
However I think Apple did not implement abstract classes because it generally uses the delegate+protocol pattern instead. For example the same pattern above would be better done like this:
import UIKit
public class GoldenSpoonChild
{
private var delegate: IStomach!;
internal init(){}
internal func setup(delegate: IStomach)
{
self.delegate = delegate;
}
public func getFoodToEat()->String
{
if(self.delegate.iAmHungry())
{
return self._myFavoriteFood();
}else{
return "";
}
}
private func _myFavoriteFood()->String
{
return "Sandwich";
}
}
public class Mother: GoldenSpoonChild, IStomach
{
private var _hungry: Bool = false;
public override init()
{
super.init();
super.setup(self);
}
public func makeFamilyHungry()->Void
{
self._hungry = true;
}
public func iAmHungry()->Bool
{
return self._hungry;
}
}
protocol IStomach
{
func iAmHungry()->Bool;
}
class DelegateTest: XCTestCase {
func testGetFood() {
var concreteClass: Mother = Mother();
XCTAssertEqual("", concreteClass.getFoodToEat());
concreteClass.makeFamilyHungry();
XCTAssertEqual("Sandwich", concreteClass.getFoodToEat());
}
}
I needed this kind of pattern because I wanted to commonize some methods in UITableViewController such as viewWillAppear etc. Was this helpful?
There is a way for simulating abstract classes using Protocols.
This is an example:
protocol MyProtocol {
func doIt()
}
class BaseClass {
weak var myDelegate: MyProtocol?
init() {
...
}
func myFunc() {
...
self.myDelegate?.doIt()
...
}
}
class ChildClass: BaseClass, MyProtocol {
override init(){
super.init()
self.myDelegate = self
}
func doIt() {
// Custom implementation
}
}
One more way how you can implement abstract class is to block initializer.
I've done it this way:
class Element:CALayer { // IT'S ABSTRACT CLASS
override init(){
super.init()
if self.dynamicType === Element.self {
fatalError("Element is abstract class, do not try to create instance of this class")
}
}
}
It's a really old question but still… Here's a snippet of actual code that compiles on Swift 5.2 and works as intended:
protocol Context {
init() throws
func out(_ aStr: String) throws
// Other stuff
}
class AbstractContext: Context {
required init() throws {
if Self.self === AbstractContext.self {
preconditionFailure("Call to abstract method \(Self.self).\(#function)")
}
}
func out(_ aStr: String) throws {
preconditionFailure("Call to abstract method \(Self.self).\(#function)")
}
// Other stuff
}
class CompileContext: AbstractContext {
required init() throws {}
override func out(_ aStr: String) throws {
print(aStr)
}
// Other stuff
}
And here's what I get once I remove CompileContext.out:
Fatal error: Call to abstract method CompileContext.out(_:): file swiftpg/contexts.swift, line 28
With the limitation of no dynamic dispatch, you could do something like this:
import Foundation
protocol foo {
static var instance: foo? { get }
func prt()
}
extension foo {
func prt() {
if Thread.callStackSymbols.count > 30 {
print("super")
} else {
Self.instance?.prt()
}
}
}
class foo1 : foo {
static var instance : foo? = nil
init() {
foo1.instance = self
}
func prt() {
print("foo1")
}
}
class foo2 : foo {
static var instance : foo? = nil
init() {
foo2.instance = self
}
func prt() {
print("foo2")
}
}
class foo3 : foo {
static var instance : foo? = nil
init() {
foo3.instance = self
}
}
var f1 : foo = foo1()
f1.prt()
var f2 : foo = foo2()
f2.prt()
var f3 : foo = foo3()
f3.prt()
I was trying to make a Weather abstract class, but using protocols wasn't ideal since I had to write the same init methods over and over again. Extending the protocol and writing an init method had it's issues, especially since I was using NSObject conforming to NSCoding.
So I came up with this for the NSCoding conformance:
required init?(coder aDecoder: NSCoder) {
guard type(of: self) != Weather.self else {
fatalError("<Weather> This is an abstract class. Use a subclass of `Weather`.")
}
// Initialize...
}
As for init:
fileprivate init(param: Any...) {
// Initialize
}
Move all references to abstract properties and methods of Base class to protocol extension implementation, where Self constraint to Base class. You will gain access to all methods and properties of Base class. Additionally compiler check implementation of abstract methods and properties in protocol for derived classes
protocol Commom:class{
var tableView:UITableView {get};
func update();
}
class Base{
var total:Int = 0;
}
extension Common where Self:Base{
func update(){
total += 1;
tableView.reloadData();
}
}
class Derived:Base,Common{
var tableView:UITableView{
return owner.tableView;
}
}
I've been trying to implement a singleton to be used as a cache for photos which I uploaded to my iOS app from the web. I've attached three variants in the code below. I tried to get variant 2 working but it is causing a compiler error which I do not understand and would like to get help on what am I doing wrong. Variant 1 does the caching but I do not like the use of a global variable. Variant 3 does not do the actual caching and I believe it is because I am getting a copy in the assignment to var ic = ...., is that correct?
Any feedback and insight will be greatly appreciated.
Thanks,
Zvi
import UIKit
private var imageCache: [String: UIImage?] = [String : UIImage?]()
class ImageCache {
class var imageCache: [String : UIImage?] {
struct Static {
static var instance: [String : UIImage?]?
static var token: dispatch_once_t = 0
}
dispatch_once(&Static.token) {
Static.instance = [String : UIImage?]()
}
return Static.instance!
}
}
class ViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
imageView.image = UIImage(data: NSData(contentsOfURL: NSURL(string: "http://images.apple.com/v/iphone-5s/gallery/a/images/download/photo_1.jpg")!)!)
//variant 1 - this code is working
imageCache["photo_1"] = imageView.image
NSLog(imageCache["photo_1"] == nil ? "no good" : "cached")
//variant 2 - causing a compiler error on next line: '#lvalue $T7' is not identical to '(String, UIImage?)'
//ImageCache.imageCache["photo_1"] = imageView.image
//NSLog(ImageCache.imageCache["photo_1"] == nil ? "no good" : "cached")
//variant 3 - not doing the caching
//var ic = ImageCache.imageCache
//ic["photo_1)"] = imageView.image
//NSLog(ImageCache.imageCache["photo_1"] == nil ? "no good" : "cached")
}
}
The standard singleton pattern is:
final class Manager {
static let shared = Manager()
private init() { ... }
func foo() { ... }
}
And you'd use it like so:
Manager.shared.foo()
Credit to appzYourLife for pointing out that one should declare it final to make sure it's not accidentally subclassed as well as the use of the private access modifier for the initializer, to ensure you don't accidentally instantiate another instance. See https://stackoverflow.com/a/38793747/1271826.
So, returning to your image cache question, you would use this singleton pattern:
final class ImageCache {
static let shared = ImageCache()
/// Private image cache.
private var cache = [String: UIImage]()
// Note, this is `private` to avoid subclassing this; singletons shouldn't be subclassed.
private init() { }
/// Subscript operator to retrieve and update cache
subscript(key: String) -> UIImage? {
get {
return cache[key]
}
set (newValue) {
cache[key] = newValue
}
}
}
Then you can:
ImageCache.shared["photo1"] = image
let image2 = ImageCache.shared["photo2"])
Or
let cache = ImageCache.shared
cache["photo1"] = image
let image2 = cache["photo2"]
Having shown a simplistic singleton cache implementation above, we should note that you probably want to (a) make it thread safe by using NSCache; and (b) respond to memory pressure. So, the actual implementation is something like the following in Swift 3:
final class ImageCache: NSCache<AnyObject, UIImage> {
static let shared = ImageCache()
/// Observer for `UIApplicationDidReceiveMemoryWarningNotification`.
private var memoryWarningObserver: NSObjectProtocol!
/// Note, this is `private` to avoid subclassing this; singletons shouldn't be subclassed.
///
/// Add observer to purge cache upon memory pressure.
private override init() {
super.init()
memoryWarningObserver = NotificationCenter.default.addObserver(forName: .UIApplicationDidReceiveMemoryWarning, object: nil, queue: nil) { [weak self] notification in
self?.removeAllObjects()
}
}
/// The singleton will never be deallocated, but as a matter of defensive programming (in case this is
/// later refactored to not be a singleton), let's remove the observer if deallocated.
deinit {
NotificationCenter.default.removeObserver(memoryWarningObserver)
}
/// Subscript operation to retrieve and update
subscript(key: String) -> UIImage? {
get {
return object(forKey: key as AnyObject)
}
set (newValue) {
if let object = newValue {
setObject(object, forKey: key as AnyObject)
} else {
removeObject(forKey: key as AnyObject)
}
}
}
}
And you'd use it as follows:
ImageCache.shared["foo"] = image
And
let image = ImageCache.shared["foo"]
For Swift 2.3 example, see previous revision of this answer.
Swift 3:
class SomeClass
{
static let sharedInstance = SomeClass()
fileprivate override init() {
//This prevents others from using the default '()' initializer
super.init()
}
func sayHello()
{
print("Hello!")
}
}
Invoke some Method:
SomeClass.sharedInstance.sayHello() //--> "Hello"
Invoke some Method by creating a new class instance (fails):
SomeClass().sayHello() //--> 'SomeClass' cannot be constructed it has no accessible initailizers
Swift-5
To create a singleton class:
import UIKit
final class SharedData: NSObject {
static let sharedInstance = SharedData()
private override init() { }
func methodName() { }
}
To access
let sharedClass = SharedClass.sharedInstance
OR
SharedClass.sharedInstance.methodName()
Following are the two different approaches to create your singleton class in swift 2.0
Approach 1) This approach is Objective C implementation over swift.
import UIKit
class SomeManager: NSObject {
class var sharedInstance : SomeManager {
struct managerStruct {
static var onceToken : dispatch_once_t = 0
static var sharedObject : SomeManager? = nil
}
dispatch_once(&managerStruct.onceToken) { () -> Void in
managerStruct.sharedObject = SomeManager()
}
return managerStruct.sharedObject!
}
func someMethod(){
print("Some method call")
}
}
Approach 2) One line Singleton, Don't forget to implement the Private init (restrict usage of only singleton)
import UIKit
class SomeManager: NSObject {
static let sharedInstance = SomeManager()
private override init() {
}
func someMethod(){
print("Some method call")
}
}
Call the Singleton method like :
SomeManager.sharedInstance.someMethod()