Swift 2.0: Protocol Extension Class Method returning Self - swift

In order to extend some functionalities of my NSManagedObject subclasses, I have defined a series of protocols:
protocol ManagedObjectFindable {
static func find(format:String, arguments: [AnyObject]?, inContext context:NSManagedObjectContext, entityName:String?) -> Self?
}
protocol UniquelyIdentifiable: ManagedObjectFindable {
var identifier: NSNumber? { get }
static func findWithIdentifier(identifier: Int, inContext context:NSManagedObjectContext) -> Self?
}
So then every NSManagedObject that has identifier in its data model entity can conform to UniquelyIdentifiable.
For that purpose I am utilising Swift 2.0 Protocol Extensions, where:
extension UniquelyIdentifiable {
static func findWithIdentifier(identifier: Int, inContext context:NSManagedObjectContext) -> Self? {
return self.find("identifier == %lld", arguments: [NSNumber(longLong: Int64(identifier))], inContext: context, entityName:nil)
}
}
Where find is defined as:
extension NSManagedObject: ManagedObjectFindable {
/** returns single entity if found, nil otherwise */
class func find(format:String, arguments: [AnyObject]?, inContext context:NSManagedObjectContext, entityName:String? = nil) -> Self? {
let objectEntityName:String
if let name = entityName {
objectEntityName = name
} else {
objectEntityName = String(self)
}
let fetchRequest = NSFetchRequest()
fetchRequest.entity = NSEntityDescription.entityForName(objectEntityName, inManagedObjectContext: context)
fetchRequest.fetchLimit = 1
fetchRequest.predicate = NSPredicate(format: format, argumentArray: arguments)
var persistentEntityº:NSManagedObject?
context.performBlockAndWait {
do {
let fetchResults = try context.executeFetchRequest(fetchRequest)
if (fetchResults.count != 0){
persistentEntityº = fetchResults.first as? NSManagedObject
}
} catch {}
}
if let persistentEntity = persistentEntityº {
return _safeObjectSelfCast(persistentEntity)
} else {
return nil
}
}
}
func _unsafeObjectSelfCast<T>(obj: AnyObject!) -> T { return obj as! T }
func _safeObjectSelfCast<T>(obj: AnyObject) -> T? { return obj as? T }
Now these methods correctly return Self? and compiler is silent on the coding time, however when compiling it gives me that error Method 'findWithIdentifier(_:inContext:)' in non-final class must return 'Self' to conform to protocol 'UniquelyIdentifiable'
Now the thing is that if instead of implementing that method in a protocol extension I would just extend my NSManagedObject subclass, it will go fine, but that kills the purpose of protocol extensions, when you are completely duplicating the same code across dozens of your NSManagedObject subclasses.
Any workaround, or I am really missing something?

Short answer:
Change Self? in extension to the NSManagedObject?.
Long answer: Self in protocol requirement acts as a placeholder for the class that will implement that protocol. So if you have
protocol SomeProtocol {
func returnSomething() -> Self
}
That means that if you implement it on Int, function returnSomething() should return Int, and if you implement it on Double it should return Double.
Since you are implementing UniquelyIdentifiable on NSManagedObject and your protocol has Self? requirement, you should return NSManagedObject?.

Related

Implement Decorator Pattern with generics in Swift

I am new to Swift, but I have plenty of experience in other languages like Java, Kotlin, Javascript, etc. It's possible that what I want to do is not supported by the language, and I've poured over the Swift Language Guide looking for the answer.
I want to implement the decorator pattern, using generics. I easily did this in Kotlin, and I'm porting the library to Swift.
class Result<T> {
let result: T?
let error: NSError?
init(result: T?, error: NSError?) {
self.result = result
self.error = error
}
}
protocol DoSomething {
associatedtype T
func doSomething() -> Result<T>
}
protocol StoreSomething {
associatedtype T
func storeSomething(thing: Result<T>)
}
/*
* DOES NOT COMPILE
*/
class StoringSomething<T> {
private let delegate: DoSomething
private let store: StoreSomething
init(delegate: DoSomething, store: StoreSomething) {
self.delegate = delegate
self.store = store
}
func doSomething() -> Result<T> {
let result = delegate.doSomething()
store.storeSomething(thing: result)
return result
}
}
I get a Protocol 'DoSomething' can only be used as a generic constraint because it has Self or associated type requirements error from the compiler. I've tried using a typealias and other ideas from SO and the Swift manual.
Thanks to #Sweeper's suggestion on associatedtype erasure you can implement the Decorator pattern with generics like so:
class AnyDoSomething<T>: DoSomething {
func doSomething() -> Result<T> {
fatalError("Must implement")
}
}
class AnyStoreSomething<T>: StoreSomething {
func storeSomething(thing: Result<T>) {
fatalError("Must implement")
}
}
class StoringSomething<T>: DoSomething {
private let delegate: AnyDoSomething<T>
private let store: AnyStoreSomething<T>
init(delegate: AnyDoSomething<T>, store: AnyStoreSomething<T>) {
self.delegate = delegate
self.store = store
}
func doSomething() -> Result<T> {
let result = delegate.doSomething()
store.storeSomething(thing: result)
return result
}
}
class DoSomethingNice<T>: AnyDoSomething<T> {
override func doSomething() -> Result<T> {
}
}

Swift UITextField target-actions as closure, problem with not removing target-actions

I have such code a little modified from code of Eric Armstrong
Adding a closure as target to a UIButton
But there is the problem with both codes. Those from Eric does remove all target-actions on
func removeTarget(for controlEvent: UIControl.Event = .touchUpInside)
And modified code on the other hand do not remove target-actions at all. Of course it is caused by if condition, but it also means that there are no targets stored properly in Storable property.
extension UIControl: ExtensionPropertyStorable {
class Property: PropertyProvider {
static var property = NSMutableDictionary()
static func makeProperty() -> NSMutableDictionary? {
return NSMutableDictionary()
}
}
func addTarget(for controlEvent: UIControl.Event = .touchUpInside, target: #escaping (_ sender: Any) ->()) {
let key = String(describing: controlEvent)
let target = Target(target: target)
addTarget(target, action: target.action, for: controlEvent)
property[key] = target
}
func removeTarget(for controlEvent: UIControl.Event = .touchUpInside) {
let key = String(describing: controlEvent)
if let target = property[key] as? Target {
removeTarget(target, action: target.action, for: controlEvent)
property[key] = nil
}
}
}
// Wrapper class for the selector
class Target {
private let t: (_ sender: Any) -> ()
init(target t: #escaping (_ sender: Any) -> ()) { self.t = t }
#objc private func s(_ sender: Any) { t(sender) }
public var action: Selector {
return #selector(s(_:))
}
}
// Protocols with associatedtypes so we can hide the objc_ code
protocol PropertyProvider {
associatedtype PropertyType: Any
static var property: PropertyType { get set }
static func makeProperty() -> PropertyType?
}
extension PropertyProvider {
static func makeProperty() -> PropertyType? {
return nil
}
}
protocol ExtensionPropertyStorable: class {
associatedtype Property: PropertyProvider
}
// Extension to make the property default and available
extension ExtensionPropertyStorable {
typealias Storable = Property.PropertyType
var property: Storable {
get {
let key = String(describing: type(of: Storable.self))
guard let obj = objc_getAssociatedObject(self, key) as? Storable else {
if let property = Property.makeProperty() {
objc_setAssociatedObject(self, key, property, .OBJC_ASSOCIATION_RETAIN)
}
return objc_getAssociatedObject(self, key) as? Storable ?? Property.property
}
return obj
}
set {
let key = String(describing: type(of: Storable.self))
return objc_setAssociatedObject(self, key, newValue, .OBJC_ASSOCIATION_RETAIN) }
}
}
My aim is to precisely register target-actions with closures and remove them without removing all other target-actions added to given UITextField via #selector. Now I can have removed ALL or NONE of target-actions while using this approach for closure-style target actions.
UPDATE
Based on Eric Armstrong answer i have implemented my version.
But what I have experienced in version proposed by Eric was that when adding target actions to TextField on TableView list while cells appear and then removing this target actions from Text Fields while cells diseappear the previous code seems to remove all target actions on removeTarget(for:) exection. So when in other place in code like UITableViewCell I have added additional target action on totaly different target (UITableViewCell object, not this custom Target() objects) while cells was disappearing and then again appearing on screen and removeTarget(for) was executed then this other (external as I call them target actions) also was removed and never called again.
I consider that some problem was usage of [String: Target] dictionary which is value type and it was used in case of property getter in objc_getAssociatedObject where there was
objc_getAssociatedObject(self, key) as? Storable ?? Property.property
So as I understand it then there wasn't objc object for given key and Storable was nil and nil-coalescing operator was called and static value type Property.property return aka [String : Dictionary]
So it was returned by copy and Target object was stored in this copied object which wasn't permanently stored and accessed in removeTarget(for:) always as nil. So nil was passed to UIControl.removetTarget() and all target actions was always cleared!.
I have tried simple replacing [String: Target] Swift dictionary with NSMutableDictionary which is a reference type so I assume it can be stored. But this simple replacement for static variable and just returning it via nil-coalesing operator caused as I assume that there as only one such storage for Target objects and then while scrolling Table View each removeForTarget() has somehow remove all target actions from all UITextFields not only from current.
I also consider usage of String(describing: type(of: Storable.self)) as being wrong as it will be always the same for given Storable type.
Ok, I think I finally solved this issue
The main problem was usage of AssociatedKey! it needs to be done like below
https://stackoverflow.com/a/48731142/4415642
So I ended up with such code:
import UIKit
/**
* Swift 4.2 for UIControl and UIGestureRecognizer,
* and and remove targets through swift extension
* stored property paradigm.
* https://stackoverflow.com/a/52796515/4415642
**/
extension UIControl: ExtensionPropertyStorable {
class Property: PropertyProvider {
static var property = NSMutableDictionary()
static func makeProperty() -> NSMutableDictionary? {
return NSMutableDictionary()
}
}
func addTarget(for controlEvent: UIControl.Event = .touchUpInside, target: #escaping (_ sender: Any) ->()) {
let key = String(describing: controlEvent)
let target = Target(target: target)
addTarget(target, action: target.action, for: controlEvent)
property[key] = target
print("ADDED \(ObjectIdentifier(target)), \(target.action)")
}
func removeTarget(for controlEvent: UIControl.Event = .touchUpInside) {
let key = String(describing: controlEvent)
if let target = property[key] as? Target {
print("REMOVE \(ObjectIdentifier(target)), \(target.action)")
removeTarget(target, action: target.action, for: controlEvent)
property[key] = nil
}
}
}
extension UIGestureRecognizer: ExtensionPropertyStorable {
class Property: PropertyProvider {
static var property: Target?
}
func addTarget(target: #escaping (Any) -> ()) {
let target = Target(target: target)
addTarget(target, action: target.action)
property = target
}
func removeTarget() {
let target = property
removeTarget(target, action: target?.action)
property = nil
}
}
// Wrapper class for the selector
class Target {
private let t: (_ sender: Any) -> ()
init(target t: #escaping (_ sender: Any) -> ()) { self.t = t }
#objc private func s(_ sender: Any) { t(sender) }
public var action: Selector {
return #selector(s(_:))
}
deinit {
print("Deinit target: \(ObjectIdentifier(self))")
}
}
// Protocols with associatedtypes so we can hide the objc_ code
protocol PropertyProvider {
associatedtype PropertyType: Any
static var property: PropertyType { get set }
static func makeProperty() -> PropertyType?
}
extension PropertyProvider {
static func makeProperty() -> PropertyType? {
return nil
}
}
protocol ExtensionPropertyStorable: class {
associatedtype Property: PropertyProvider
}
// Extension to make the property default and available
extension ExtensionPropertyStorable {
typealias Storable = Property.PropertyType
var property: Storable {
get {
guard let obj = objc_getAssociatedObject(self, &AssociatedKeys.property) as? Storable else {
if let property = Property.makeProperty() {
objc_setAssociatedObject(self, &AssociatedKeys.property, property, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
return objc_getAssociatedObject(self, &AssociatedKeys.property) as? Storable ?? Property.property
}
return obj
}
set {
return objc_setAssociatedObject(self, &AssociatedKeys.property, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) }
}
}
private struct AssociatedKeys {
static var property = "AssociatedKeys.property"
}

Generic Return Type Based on Class

I'm trying to create factory method on a class that automatically casts to the class it's on.
extension NSObject {
// how can I get the return type to be the current NSObject subclass
// instead of NSObject?
class func create() -> NSObject {
return self.init()
}
// example: create(type: NSArray.self)
class func create<T:NSObject>(type:T.Type) -> T {
return T()
}
}
Example two works, but gets NO advantage from being a class method:
let result = NSArray.create(type: NSArray.self)
But I'd love to be able to just call:
let result = NSArray.create()
without having to cast afterwards. Is there a way to do this in Swift?
You can use the class-level Self for this:
extension NSObject {
class func create() -> Self {
return self.init()
}
}
let array = NSArray.create()
But I don't really see why you would, since you might as well just add an initializer.
The accepted answer does the trick, thanks!
However, I needed this for a case where I wasn't calling the init directly. Instead, I had an object that was of type NSObject and needed a forced downcast
As #Hamish pointed out from this other SO answer, you can use the generic inference on a class method if you're another layer deep (a method called by a class method).
class func create() -> Self {
return createInner()
}
class func createInner<T>() -> T {
// upcasting to NSObject to show that we can downcast
let b = self.init() as NSObject
return b as! T
}
let array = NSArray.create() // gives me an NSArray
An Example with CoreData
I still can't figure out how to get the fetch part to compile, so I'm using an external function still.
import CoreData
// callers use
// try fetch(type: SomeMO.self, moc: moc)
func fetch<T:NSManagedObject>(type:T.Type, moc:NSManagedObjectContext) throws -> [T] {
return try T.fetch(moc: moc) as! [T]
}
extension NSManagedObject {
class func makeOne(moc:NSManagedObjectContext) -> Self {
return makeOneInner(moc: moc)
}
private class func makeOneInner<T>(moc:NSManagedObjectContext) -> T {
let name = "\(self)"
let retVal = NSEntityDescription.insertNewObject(forEntityName: name, into: moc)
return retVal as! T
}
class func fetch(moc:NSManagedObjectContext) throws -> [NSManagedObject] {
let fetchReq:NSFetchRequest<NSManagedObject> = self.fetchRequest() as! NSFetchRequest<NSManagedObject>
let retVal = try moc.fetch(fetchReq) as [NSManagedObject]
return retVal
}
}

Swift Protocol as Generic Parameter

Given this class:
class ServiceRegistry {
var store = [String : AnyObject]()
var allRegisteredType: [String] {
return store.map { $0.0 }
}
func registerInstance<T>(instance:AnyObject, forType type: T.Type) {
store[String(type)] = instance
}
func instanceForType<T>(type: T.Type) -> T? {
return store[String(type)] as? T
}
}
Is there a way I can enforce that T must be a Protocol, without using the #obj?
This is a modified version of my type assertion technique. I added the "as? AnyClass" assert so that the type can only be of protocol type. There might be a more elegant way of doing this but going through my notes and research about class assertion this is what I came up with.
import Foundation
protocol IDescribable:class{}
class A:IDescribable{}
class B:A{}
let a = A()
let b = B()
func ofType<T>(instance:Any?,_ type:T.Type) -> T?{/*<--we use the ? char so that it can also return a nil*/
if(instance as? T != nil && type as? AnyClass == nil){return instance as? T}
return nil
}
Swift.print(ofType(a,A.self))//nil
Swift.print(ofType(a,IDescribable.self))//A
Swift.print(ofType(b,B.self))//nil

Using as a concrete type conforming to protocol AnyObject is not supported

I'm using Swift 2 and using WeakContainer as a way to store a set of weak objects, much like NSHashTable.weakObjectsHashTable()
struct WeakContainer<T: AnyObject> {
weak var value: T?
}
public protocol MyDelegate : AnyObject {
}
Then in my ViewController, I declare
public var delegates = [WeakContainer<MyDelegate>]
But it is error
Using MyDelegate as a concrete type conforming to protocol AnyObject is not supported
I see that the error is that WeakContainer has value member declared as weak, so T is expected to be object. But I also declare MyDelegate as AnyObject, too. How to get around this?
I ran into the same problem when I tried to implement weak containers. As #plivesey points out in a comment above, this seems to be a bug in Swift 2.2 / Xcode 7.3, but it is expected to work.
However, the problem does not occur for some Foundation protocols. For example, this compiles:
let container = WeakContainer<NSCacheDelegate>()
I found out that this works for protocols marked with the #objc attribute. You can use this as a workaround:
Workaround 1
#objc
public protocol MyDelegate : AnyObject { }
let container = WeakContainer<MyDelegate>() // No compiler error
As this can lead to other problems (some types cannot be represented in Objective-C), here is an alternative approach:
Workaround 2
Drop the AnyObject requirement from the container, and cast the value to AnyObject internally.
struct WeakContainer<T> {
private weak var _value:AnyObject?
var value: T? {
get {
return _value as? T
}
set {
_value = newValue as? AnyObject
}
}
}
protocol MyDelegate : AnyObject { }
var container = WeakContainer<MyDelegate>() // No compiler error
Caveat: Setting a value that conforms to T, but is not an AnyObject, fails.
I had the same idea to create weak container with generics.
As result I created wrapper for NSHashTable and did some workaround for your compiler error.
class WeakSet<ObjectType>: SequenceType {
var count: Int {
return weakStorage.count
}
private let weakStorage = NSHashTable.weakObjectsHashTable()
func addObject(object: ObjectType) {
guard object is AnyObject else { fatalError("Object (\(object)) should be subclass of AnyObject") }
weakStorage.addObject(object as? AnyObject)
}
func removeObject(object: ObjectType) {
guard object is AnyObject else { fatalError("Object (\(object)) should be subclass of AnyObject") }
weakStorage.removeObject(object as? AnyObject)
}
func removeAllObjects() {
weakStorage.removeAllObjects()
}
func containsObject(object: ObjectType) -> Bool {
guard object is AnyObject else { fatalError("Object (\(object)) should be subclass of AnyObject") }
return weakStorage.containsObject(object as? AnyObject)
}
func generate() -> AnyGenerator<ObjectType> {
let enumerator = weakStorage.objectEnumerator()
return anyGenerator {
return enumerator.nextObject() as! ObjectType?
}
}
}
Usage:
protocol MyDelegate : AnyObject {
func doWork()
}
class MyClass: AnyObject, MyDelegate {
fun doWork() {
// Do delegated work.
}
}
var delegates = WeakSet<MyDelegate>()
delegates.addObject(MyClass())
for delegate in delegates {
delegate.doWork()
}
It's not the best solution, because WeakSet can be initialized with any type, and if this type doesn't conform to AnyObject protocol then app will crash. But I don't see any better solution right now.
Why are you trying to use generics? I would suggest doing the following:
import Foundation
import UIKit
protocol MyDelegate : AnyObject {
}
class WeakContainer : AnyObject {
weak var value: MyDelegate?
}
class ViewController: UIViewController {
var delegates = [WeakContainer]()
}
There is also NSValue's nonretainedObject
If your Protocol can be marked as #obj then you can use code below
protocol Observerable {
associatedtype P : AnyObject
var delegates: NSHashTable<P> { get }
}
#objc protocol MyProtocol {
func someFunc()
}
class SomeClass : Observerable {
var delegates = NSHashTable<MyProtocol>.weakObjects()
}
Your issue is that WeakContainer requires its generic type T to be a subtype of AnyObject - a protocol declaration is not a subtype of AnyObject. You have four options:
Instead of declaring WeakContainer<MyDelegate> replace it with something that actually implements MyDelegate. The Swift-y approach for this is to use the AnyX pattern: struct AnyMyDelegate : MyDelegate { ... }
Define MyDelegate to be 'class bound' as protocol MyDelegate : class { ... }
Annotate MyDelegate with #obj which, essentially, makes it 'class bound'
Reformulate WeakContainer to not require its generic type to inherit from AnyObject. You'll be hard pressed to make this work because you need a property declared as weak var and there are limitation as to what types are accepted by weak var - which are AnyObject essentially.
Here is my implementation of WeakSet in pure Swift (without NSHashTable).
internal struct WeakBox<T: AnyObject> {
internal private(set) weak var value: T?
private var pointer: UnsafePointer<Void>
internal init(_ value: T) {
self.value = value
self.pointer = unsafeAddressOf(value)
}
}
extension WeakBox: Hashable {
var hashValue: Int {
return self.pointer.hashValue
}
}
extension WeakBox: Equatable {}
func ==<T>(lhs: WeakBox<T>, rhs: WeakBox<T>) -> Bool {
return lhs.pointer == rhs.pointer
}
public struct WeakSet<Element>: SequenceType {
private var boxes = Set<WeakBox<AnyObject>>()
public mutating func insert(member: Element) {
guard let object = member as? AnyObject else {
fatalError("WeakSet's member (\(member)) must conform to AnyObject protocol.")
}
self.boxes.insert(WeakBox(object))
}
public mutating func remove(member: Element) {
guard let object = member as? AnyObject else {
fatalError("WeakSet's member (\(member)) must conform to AnyObject protocol.")
}
self.boxes.remove(WeakBox(object))
}
public mutating func removeAll() {
self.boxes.removeAll()
}
public func contains(member: Element) -> Bool {
guard let object = member as? AnyObject else {
fatalError("WeakSet's member (\(member)) must conform to AnyObject protocol.")
}
return self.boxes.contains(WeakBox(object))
}
public func generate() -> AnyGenerator<Element> {
var generator = self.boxes.generate()
return AnyGenerator {
while(true) {
guard let box = generator.next() else {
return nil
}
guard let element = box.value else {
continue
}
return element as? Element
}
}
}
}