SWIFT 3.0 migration error - Extension of a generic Obj-C class cannot access the class' generic parameter at runtime - objective-c

I have this code working fine in Swift 2.
extension PHFetchResult: Sequence {
public func makeIterator() -> NSFastEnumerationIterator {
return NSFastEnumerationIterator(self)
}
}
Since I upgraded to Swift 3
Extension of a generic Objective-C class cannot access the class's generic parameters at runtime
I have no idea on how to fix this. Any help is much appreciated!

Problem was reported here: https://bugs.swift.org/browse/SR-1576
But in the end you can't use for in with PHFetchResult in Swift 3.0. Let's see some examples:
let collections = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .any, options: nil)
let collectionLists = PHCollectionList.fetchCollectionLists(with: .momentList, subtype: .momentListYear, options: nil)
let assets = PHAsset.fetchAssets(with: .image, options: nil)
You can either use the built-in enumeration of PHFetchResult (my recommended solution):
collections.enumerateObjects(_:) { (collection, count, stop) in
//...
}
collectionLists.enumerateObjects(_:) { (collectionList, count, stop) in
//...
}
assets.enumerateObjects(_:) { (asset, count, stop) in
//...
}
Or access each object by its index:
for idx in 0 ..< collections.count {
let collection = collections[idx]
// ...
}
for idx in 0 ..< collectionLists.count {
let collectionList = collectionLists[idx]
// ...
}
for idx in 0 ..< assets.count {
let asset = assets[idx]
// ...
}

Pulling from Realm, you may be able to get around this by extending a subclass of what you want to conform to Sequence and put the makeIerator function there.
// Sequence conformance for ClassA is provided by ProtocolX's `makeIterator()` implementation.
extension ClassA: Sequence {}
extension ProtocolX {
// Support Sequence-style enumeration
public func makeIterator() -> RLMIterator {
return RLMIterator(collection: self)
}
}
You can see the full code at https://github.com/realm/realm-cocoa/blob/master/Realm/Swift/RLMSupport.swift

You can use a wrapper type as suggested by Swift engineer Jordan Rose on the bug report:
import Photos
struct ResultSequence<Element: AnyObject>: Sequence {
var result: PHFetchResult<Element>
init(_ result: PHFetchResult<Element>) {
self.result = result
}
func makeIterator() -> NSFastEnumerationIterator {
return NSFastEnumerationIterator(self.result)
}
}
func test(_ request: PHFetchResult<PHCollection>) {
for elem in ResultSequence(request) {
print(elem)
}
}

There is no way to fix that, you might need to refactor your code or use some other techniques.
you can refer to this:
How to use a swift class with a generic type in objective c
docs:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html#//apple_ref/doc/uid/TP40014216-CH10-XID_78

Related

How do we return an optional enum value from Swift to Obj-C?

We know how to expose Swift enums to Obj-C:
#objc enum Animal: Int {
case Cat, Dog
}
But the compiler complains that the following "cannot be represented in Obj-C":
func myAnimal() -> Animal? {
if hasPet() {
return .Cat
} else {
return nil
}
}
Ideas?
Optional Ints in Swift don't map to a type in Objective-C. The issue is that your myAnimal() method is returning a type that can't be represented in Objective-C.
The way I see it, you have two options...
Option1: Change your method's return type:
func myAnimal() -> NSNumber? {
// method body goes here.
}
This doesn't really seem great since in Objective-C you'd have to do something like this:
if (myAnimal().integerValue == AnimalCat) {
// do stuff here
}
Option 2: Add a catch-all case in your enum
#objc enum Animal: Int {
case none = 0
case cat = 1
case dog = 2
init(rawValue: Int) {
switch rawValue {
case 1: self = Cat
case 2: self = Dog
default: self = None
}
}
}
// Updated method signature that makes the compiler happy.
func myAnimal() -> Animal {
if hasPet() {
return .Cat
} else {
return .None
}
}
This way, you can change your method signature to not return an optional, and the compiler will be happy.

Shouldn't every .swift file be a class?

I have some experience in ObjC and I just started learning Swift. In Objc everything is a class through #interface in .h and #implementation of .m, or in other Swift classes that I have seen everything is usually in some form of
class MyCustomClassInhertingfrom: SomeFoundationClass { //methods & properties}
Yet here in some class named pancakeHouse.Swift there is no mention of the keyword class WHY? Isn't this a Model Class? Doesn't this break the MVC design pattern? Is this happening because of new powerful features of enums& structs vs class in Swift?_____I am confused obviously!
import UIKit
import CoreLocation
enum PriceGuide : Int {
case Unknown = 0
case Low = 1
case Medium = 2
case High = 3
}
extension PriceGuide : CustomStringConvertible {
var description : String {
switch self {
case .Unknown:
return "?"
case .Low:
return "$"
case .Medium:
return "$$"
case .High:
return "$$$"
}
}
}
enum PancakeRating {
case Unknown
case Rating(Int)
}
extension PancakeRating {
init?(value: Int) {
if value > 0 && value <= 5 {
self = .Rating(value)
} else {
self = .Unknown
}
}
}
extension PancakeRating {
var ratingImage : UIImage? {
guard let baseName = ratingImageName else {
return nil
}
return UIImage(named: baseName)
}
var smallRatingImage : UIImage? {
guard let baseName = ratingImageName else {
return nil
}
return UIImage(named: "\(baseName)_small")
}
private var ratingImageName : String? {
switch self {
case .Unknown:
return nil
case .Rating(let value):
return "pancake_rate_\(value)"
}
}
}
struct PancakeHouse {
let name: String
let photo: UIImage?
let thumbnail: UIImage?
let priceGuide: PriceGuide
let location: CLLocationCoordinate2D?
let details: String
let rating: PancakeRating
}
extension PancakeHouse {
init?(dict: [String : AnyObject]) {
guard let name = dict["name"] as? String,
let priceGuideRaw = dict["priceGuide"] as? Int,
let priceGuide = PriceGuide(rawValue: priceGuideRaw),
let details = dict["details"] as? String,
let ratingRaw = dict["rating"] as? Int,
let rating = PancakeRating(value: ratingRaw) else {
return nil
}
self.name = name
self.priceGuide = priceGuide
self.details = details
self.rating = rating
if let imageName = dict["imageName"] as? String where !imageName.isEmpty {
photo = UIImage(named: imageName)
} else {
photo = nil
}
if let thumbnailName = dict["thumbnailName"] as? String where !thumbnailName.isEmpty {
thumbnail = UIImage(named: thumbnailName)
} else {
thumbnail = nil
}
if let latitude = dict["latitude"] as? Double,
let longitude = dict["longitude"] as? Double {
location = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
} else {
location = nil
}
}
}
extension PancakeHouse {
static func loadDefaultPancakeHouses() -> [PancakeHouse]? {
return self.loadPancakeHousesFromPlistNamed("pancake_houses")
}
static func loadPancakeHousesFromPlistNamed(plistName: String) -> [PancakeHouse]? {
guard let path = NSBundle.mainBundle().pathForResource(plistName, ofType: "plist"),
let array = NSArray(contentsOfFile: path) as? [[String : AnyObject]] else {
return nil
}
return array.map { PancakeHouse(dict: $0) }
.filter { $0 != nil }
.map { $0! }
}
}
extension PancakeHouse : CustomStringConvertible {
var description : String {
return "\(name) :: \(details)"
}
}
extension PancakeHouse: Equatable {
}
func ==(lhs: PancakeHouse, rhs: PancakeHouse) -> Bool {
return lhs.name == rhs.name
}
Note: I would appreciate an answer that also includes comparison of the .swift vs .h + .m ie don't just consider this as a specific question, consider it as a general question and explain or link the prerequisites's details needed to understand this question)
pancakeHouse.swift defines PancakeHouse and all the various things that go with it. That is perfectly good Swift style. There is no class here because PancakeHouse happens to be a struct, which is also perfectly good Swift style (and mildly preferred). Structs are much like classes in Swift, in that they can have data and methods (and extensions).
ObjC does not require that each class be defined in its own .h/.m pair, but it is fairly typical ObjC style to do so. That said, even in ObjC there are exceptions. It is common to have mutable subclasses defined in the same file as their base class (NSArray and NSMutableArray are both defined in NSArray.h). Swift style has evolved towards lumping related things together more closely. One style makes it easier to find something if you know its name. The other makes it easier to find related concepts together. Both have their advantages, and once people are used to one they tend to believe that that one is obviously correct. But they're just different ways of organizing.
Note that this file also makes use of Swift extensions to break up related methods. That is also common and good Swift. Old ObjC did that with categories, but it's much less common to organize ObjC code that way today (categories are used for other things now). Again, neither is deeply correct. It's just the styles that have evolved.
Swift files just need valid swift code. That's all. In this case, your swift file is just defining two enums. Generally it's better practice to put each enum (and its extension) in it's own .swift file, but that's really just personal opinion when you get right down to it.
A .m is the implementation of the .h interface. It's a pain in the !##$ to keep those two things always up to date. Swift makes this much easier by just merging them into one thing/file, and your entire project automatically sees it based on the access you've set. If you don't set any access, like the example above, then you have 'internal' which means the whole project.
There are two philosophies the compiler writers could take on this question:
Each public class needs a file with the matching name - this is Java's way of doing it. Although it is minimally restrictive, the logic behind it is to let the compiler find class references without looking through all the files. It also helps programmers organize their code.
Do it your own way - this is the road taken by Swift, along with C, C#, Objective-C. Essentially, compiler writers tell you that their compiler will find your classes no matter where you put them, letting you organize your code in a way that you find the most intuitive for you and your team.

Call generic function from non-generic function in Swift

MMCondition is a protocol defined in Swift, but interoperates with Objective-C (annotated with #objc).
#objc public protocol MMCondition {
static var name: String { get }
static var isMutuallyExclusive: Bool { get }
}
I have the following code:
// addCondition cannot be generic as I want it to be accessible from Objective-C as well.
public func addCondition(condition: MMCondition) {
// How do I initialize OperationConditionImplementer here?
let operationCondition = OperationConditionImplementer(condition: condition) // doesn't compile
// Error: Cannot invoke initializer for type 'OperationConditionImplementer<T>' with an argument list of type '(condition: MMCondition)'
// Can I use condition.dynamicType to init OperationConditionImplementer somehow?
}
struct OperationConditionImplementer<T: MMCondition> {
let condition: T
static var name: String {
return "Silent<\(T.name)>"
}
static var isMutuallyExclusive: Bool {
return T.isMutuallyExclusive
}
init(condition: T) {
self.condition = condition
}
}
From Objective-C, you can't use generics as stated in the documentation.
You’ll have access to anything within a class or protocol that’s
marked with the #objc attribute as long as it’s compatible with
Objective-C. This excludes Swift-only features such as those listed
here:
Generics
...
So you need to remove completely the generics code. One possible solution might be:
#objc protocol MMCondition {
static var name: String { get }
static var isMutuallyExclusive: Bool { get }
}
struct OperationConditionImplementer {
let condition: MMCondition
var name: String {
return "Silent<\(condition.dynamicType.name)>"
}
var isMutuallyExclusive: Bool {
return condition.dynamicType.isMutuallyExclusive
}
init(condition: MMCondition) {
self.condition = condition
// Here decide comparing types
if condition.dynamicType === ExampleCondition.self {
print(condition.dynamicType.name)
}
}
}
So for instance, if you try it out in a playground:
class ExampleCondition: NSObject, MMCondition {
static var name: String = "ExampleCondition"
static var isMutuallyExclusive: Bool = false
}
let example = OperationConditionImplementer(condition: ExampleCondition())
You'll see "ExampleCondition" printed.
If you eventually switch to pure Swift, you need to specify T when initializing a OperationConditionImplementer.
You can achieve that defining the addCondition method as:
func addCondition<T: MMCondition>(condition: T) {
let a = OperationConditionImplementer<T>(condition: condition)
}
Since Swift 2.0 instances of generic classes can implement Objective-C protocols. What won't be possible I believe is having a struct implement the protocol. In fact I expect that your protocol may need to inherit from NSObjectProtocol to be usable in Objective-C which would then prevent you from implementing the protocol with structs or enums.
You also rightly mention that you can't access generic functions from Objective-C.
For a concrete example of using a generic to fulfil an Objective-C protocol have a look at this blog post.

Objective-C calling parameterized Swift method crashes Swift compiler

I have a simple Swift extension on NSManagedObject, in which I have a parametrized method for finding a single object - the signature looks like:
public class func findFirst<T:NSManagedObject>(inContext context : NSManagedObjectContext? = .None) -> T?
I'm trying to call this from Objective-C, but it seems like it cannot be seen. If I create a non-parameterized version I can see and call it just fine from Objective-C:
public class func findFirstUntypedWithPredicate(predicate:NSPredicate?, inContext context : NSManagedObjectContext? = .None) -> NSManagedObject?
Is there any way for ObjectiveC to be able to reach the parameterized version of the call?
I would use Self like so:
public class func findFirst(inContext context : NSManagedObjectContext? = .None) -> Self?
using the technique found here:
How can I create instances of managed object subclasses in a NSManagedObject Swift extension?
However, that causes the Swift compiler to segfault when compiling the code (Xcode 6.3.1, or Xcode 6.4 beta 2).
Edit: Here's a link with the full source of the framework I'm trying to build, including bonus Swift compiler crashes caused by templated methods:
https://www.dropbox.com/s/fixaj9ygdoi4arp/KiGiCoreData.zip?dl=0
Generic methods are not visible from Objective-C. However you can use
the ideas from How to use generic types to get object with same type to define a findFirst() class method
which returns Self? (the Swift equivalent of instancetype) without
being generic:
// Used to cast `AnyObject?` to `Self?`, `T` is inferred from the context.
func objcast<T>(obj: AnyObject?) -> T? {
return obj as! T?
}
extension NSManagedObject
{
class func entityName() -> String {
let classString = NSStringFromClass(self)
// The entity is the last component of dot-separated class name:
let components = split(classString) { $0 == "." }
return components.last ?? classString
}
// Return any matching object, or `nil` if none exists or an error occurred
class func findFirst(context : NSManagedObjectContext, withPredicate pred : NSPredicate?) -> Self? {
let name = entityName()
let request = NSFetchRequest(entityName: name)
request.predicate = pred
var error : NSError?
let result = context.executeFetchRequest(request, error: &error)
if let objects = result {
return objcast(objects.first)
} else {
println("Fetch failed: \(error?.localizedDescription)")
return nil
}
}
}
This can be used from Swift
if let obj = YourEntity.findFirst(context, withPredicate: nil) {
// found
} else {
// not found
}
and from Objective-C:
YourEntity *obj = [YourEntity findFirst:context withPredicate:nil];

What is the Swift equivalent of respondsToSelector?

I've googled but not been able to find out what the swift equivalent to respondsToSelector: is.
This is the only thing I could find (Swift alternative to respondsToSelector:) but isn't too relevant in my case as its checking the existence of the delegate, I don't have a delegate I just want to check if a new API exists or not when running on the device and if not fall back to a previous version of the api.
As mentioned, in Swift most of the time you can achieve what you need with the ? optional unwrapper operator. This allows you to call a method on an object if and only if the object exists (not nil) and the method is implemented.
In the case where you still need respondsToSelector:, it is still there as part of the NSObject protocol.
If you are calling respondsToSelector: on an Obj-C type in Swift, then it works the same as you would expect. If you are using it on your own Swift class, you will need to ensure your class derives from NSObject.
Here's an example of a Swift class that you can check if it responds to a selector:
class Worker : NSObject
{
func work() { }
func eat(food: AnyObject) { }
func sleep(hours: Int, minutes: Int) { }
}
let worker = Worker()
let canWork = worker.respondsToSelector(Selector("work")) // true
let canEat = worker.respondsToSelector(Selector("eat:")) // true
let canSleep = worker.respondsToSelector(Selector("sleep:minutes:")) // true
let canQuit = worker.respondsToSelector(Selector("quit")) // false
It is important that you do not leave out the parameter names. In this example, Selector("sleep::") is not the same as Selector("sleep:minutes:").
There is no real Swift replacement.
You can check in the following way:
someObject.someMethod?()
This calls the method someMethod only if it's defined on object someObject but you can use it only for #objc protocols which have declared the method as optional.
Swift is inherently a safe language so everytime you call a method Swift has to know the method is there. No runtime checking is possible. You can't just call random methods on random objects.
Even in Obj-C you should avoid such things when possible because it doesn't play well with ARC (ARC then triggers warnings for performSelector:).
However, when checking for available APIs, you can still use respondsToSelector:, even if Swift, if you are dealing with NSObject instances:
#interface TestA : NSObject
- (void)someMethod;
#end
#implementation TestA
//this triggers a warning
#end
var a = TestA()
if a.respondsToSelector("someMethod") {
a.someMethod()
}
Update Mar 20, 2017 for Swift 3 syntax:
If you don't care whether the optional method exists, just call delegate?.optionalMethod?()
Otherwise, using guard is probably the best approach:
weak var delegate: SomeDelegateWithOptionals?
func someMethod() {
guard let method = delegate?.optionalMethod else {
// optional not implemented
alternativeMethod()
return
}
method()
}
Original answer:
You can use the "if let" approach to test an optional protocol like this:
weak var delegate: SomeDelegateWithOptionals?
func someMethod() {
if let delegate = delegate {
if let theMethod = delegate.theOptionalProtocolMethod? {
theMethod()
return
}
}
// Reaching here means the delegate doesn't exist or doesn't respond to the optional method
alternativeMethod()
}
If the method you are testing for is defined as an optional method in a #objc protocol (which sounds like your case), then use the optional chaining pattern as:
if let result = object.method?(args) {
/* method exists, result assigned, use result */
}
else { ... }
When the method is declare as returning Void, simply use:
if object.method?(args) { ... }
See:
“Calling Methods Through Optional Chaining”
Excerpt From: Apple Inc. “The Swift Programming Language.”
iBooks. https://itun.es/us/jEUH0.l
It seems you need to define your protocol as as subprotocol of NSObjectProtocol ... then you'll get respondsToSelector method
#objc protocol YourDelegate : NSObjectProtocol
{
func yourDelegateMethod(passObject: SomeObject)
}
note that only specifying #objc was not enough. You should be also careful that the actual delegate is a subclass of NSObject - which in Swift might not be.
For swift3
If you just want to call the method, run the code below.
self.delegate?.method?()
Functions are first-class types in Swift, so you can check whether an optional function defined in a protocol has been implemented by comparing it to nil:
if (someObject.someMethod != nil) {
someObject.someMethod!(someArgument)
} else {
// do something else
}
In Swift 2,Apple introduced a new feature called API availability checking, which might be a replacement for respondsToSelector: method.The following code snippet comparison is copied from the WWDC2015 Session 106 What's New in Swift which I thought might help you,please check it out if you need to know more.
The Old Approach:
#IBOutlet var dropButton: NSButton!
override func awakeFromNib() {
if dropButton.respondsToSelector("setSpringLoaded:") {
dropButton.springLoaded = true
}
}
The Better Approach:
#IBOutlet var dropButton: NSButton!
override func awakeFromNib() {
if #available(OSX 10.10.3, *) {
dropButton.springLoaded = true
}
}
For swift 3.0
import UIKit
#objc protocol ADelegate : NSObjectProtocol {
#objc optional func hi1()
#objc optional func hi2(message1:String, message2:String)
}
class SomeObject : NSObject {
weak var delegate:ADelegate?
func run() {
// single method
if let methodHi1 = delegate?.hi1 {
methodHi1()
} else {
print("fail h1")
}
// multiple parameters
if let methodHi2 = delegate?.hi2 {
methodHi2("superman", "batman")
} else {
print("fail h2")
}
}
}
class ViewController: UIViewController, ADelegate {
let someObject = SomeObject()
override func viewDidLoad() {
super.viewDidLoad()
someObject.delegate = self
someObject.run()
}
// MARK: ADelegate
func hi1() {
print("Hi")
}
func hi2(message1: String, message2: String) {
print("Hi \(message1) \(message2)")
}
}
Currently (Swift 2.1) you can check it using 3 ways:
Using respondsToSelector answered by #Erik_at_Digit
Using '?' answered by #Sulthan
And using as? operator:
if let delegateMe = self.delegate as? YourCustomViewController
{
delegateMe.onSuccess()
}
Basically it depends on what you are trying to achieve:
If for example your app logic need to perform some action and the delegate isn't set or the pointed delegate didn't implement the onSuccess() method (protocol method) so option 1 and 3 are the best choice, though I'd use option 3 which is Swift way.
If you don't want to do anything when delegate is nil or method isn't implemented then use option 2.
As I started to update my old project to Swift 3.2, I just needed to change the method from
respondsToSelector(selector)
to:
responds(to: selector)
I just implement this myself in a project, see code below. As mentions by #Christopher Pickslay it is important to remember that functions are first class citizens and can therefore be treated like optional variables.
#objc protocol ContactDetailsDelegate: class {
optional func deleteContact(contact: Contact) -> NSError?
}
...
weak var delegate:ContactDetailsDelegate!
if let deleteContact = delegate.deleteContact {
deleteContact(contact)
}
another possible syntax by swift..
if let delegate = self.delegate, method = delegate.somemethod{
method()
}
I use guard let else, so that can do some default stuff if the delegate func is not implemented.
#objc protocol ViewController2Delegate: NSObjectProtocol {
optional func viewController2(controller: ViewController2, didSomethingWithStringAndReturnVoid string: String)
optional func viewController2(controller: ViewController2, didSomethingWithStringAndReturnString string: String) -> String
}
class ViewController2: UIViewController {
weak var delegate: ViewController2Delegate?
#IBAction func onVoidButtonClicked(sender: AnyObject){
if (delegate != nil && delegate!.respondsToSelector(Selector("viewController2:didSomethingWithStringAndReturnVoid:"))) {
NSLog("ReturnVoid is implemented")
delegate!.viewController2!(self, didSomethingWithStringAndReturnVoid: "dummy")
}
else{
NSLog("ReturnVoid is not implemented")
// Do something by default
}
}
#IBAction func onStringButtonClicked(sender: AnyObject){
guard let result = delegate?.viewController2?(self, didSomethingWithStringAndReturnString: "dummy") else {
NSLog("ReturnString is not implemented")
// Do something by default
return
}
NSLog("ReturnString is implemented with result: \(result)")
}
}
I guess you want to make a default implementation for delegate. You can do this:
let defaultHandler = {}
(delegate?.method ?? defaultHandler)()
Swift 3:
protocol
#objc protocol SomeDelegate {
#objc optional func method()
}
Object
class SomeObject : NSObject {
weak var delegate:SomeObject?
func delegateMethod() {
if let delegateMethod = delegate?.method{
delegateMethod()
}else {
//Failed
}
}
}
The equivalent is the ? operator:
var value: NSNumber? = myQuestionableObject?.importantMethod()
importantMethod will only be called if myQuestionableObject exists and implements it.