How to have multiple definitions for a function in swift [duplicate] - ios

I am starting to learn Swift, and have been following the very good Stanford University video lectures on YouTube. Here is a link if you are interested or it helps (although it isn't required to understand my problem):
Developing iOS 8 Apps with Swift - 2. More Xcode and Swift, MVC
While following the lectures I got to a point where (as far as I could tell) my code was identical to the code in the video but on my system I got a compiler error. After a lot of trial and error I have managed to reduce my code to two examples, one of which generates an error, the other or which doesn't, but I have no idea what is actually causing the error or how to resolve it.
The code which creates the error is:
import UIKit
class BugViewController: UIViewController
{
func perform(operation: (Double) -> Double) {
}
func perform(operation: (Double, Double) -> Double) {
}
}
This creates the following compiler error:
Method 'perform' with Objective-C selector 'perform: ' conflicts with previous declaration with the same Objective-C selector
By simply removing the sub-classing of UIViewController the code compiles:
import UIKit
class BugViewController
{
func perform(operation: (Double) -> Double) {
}
func perform(operation: (Double, Double) -> Double) {
}
}
Some other information which may or may not be relevant:
I have recently upgraded to Yosemite.
When I installed Xcode, I ended up with a Beta version (Version 6.3 (6D543q)) because (if I remember correctly) this was the version I needed to run on my version of OS X.
I am half hoping this is a bug in the compiler because otherwise this doesn't make any sense to me. Any help very gratefully received!

I myself am also taking the Standford course and I got stuck here for a long time too, but after some searching, I found something from here: Xcode release notes and it mentioned something below:
Swift 1.2 is strict about checking type-based overloading of #objc
methods and initializers, something not supported by Objective-C.
// Has the Objective-C selector "performOperation:".
func performOperation(op: NSOperation) { /* do something */ }
// Also has the selector "performOperation:".
func performOperation(fn: () -> Void) {
self.performOperation(NSBlockOperation(block: fn))
}
This code would work when invoked from Swift, but could easily crash
if invoked from Objective-C. To solve this problem, use a type that is
not supported by Objective-C to prevent the Swift compiler from
exposing the member to the Objective-C runtime:
If it makes sense, mark the member as private to disable inference of #objc.
Otherwise, use a dummy parameter with a default value, for
example: _ nonobjc: () = (). (19826275)
Overrides of methods exposed
to Objective-C in private subclasses are not inferred to be #objc,
causing the Swift compiler to crash. Explicitly add the #objc
attribute to any such overriding methods. (19935352)
Symbols from SDKs are not available when using Open Quickly in a
project or workspace that uses Swift. (20349540)
what i did was just adding "private" in front of the override method like this:
private func performOperation(operation: Double -> Double) {
if operandStack.count >= 1 {
displayValue = operation(operandStack.removeLast())
enter()
}
}

Objective-C does not support method overloading, you have to use a different method name. When you inherited UIViewController you inherited NSObject and made the class interopable to Obj-C. Swift on the other hand does support overloading, that's why it works when you remove the inheritance.

As it has already been answered, ObjC doesn't support method overloading (two methods with the same name) and In swift 2 under Xcode 7 there are two options to solve this kind of problems. One option is to rename the method using the attribute: #objc(newNameMethod:)
func methodOne(par1, par2) {...}
#objc(methodTwo:)
func methodOne(par1) {...}
another option to solve this problem in Xcode 7+ is by applying #nonobjc attribute to any method, subscript or initialiser
func methodOne() {...}
#nonobjc
func methodOne() {...}

The problem is UIViewController is an #objc class. When inheriting from UIViewController, BugViewController is also a #objc class.
This means it must conform to the rules of Objective-C selectors (the name of a method). The methods func perform(operation: (Double) -> Double) and func perform(operation: (Double, Double) -> Double) both have the same selector #selector(perform:). This is not allowed.
To resolve this, use different names: like func perform1(operation: (Double) -> Double) and func perform2(operation: (Double, Double) -> Double).
I think the best way to handle this is to give your perform() methods more descriptive names. What do these methods do? How do they change the state of the view controller? Look at the other UIViewController methods to get a feel for the style of method naming, or read Method Names Should Be Expressive and Unique Within a Class

From https://developer.apple.com/library/ios/releasenotes/DeveloperTools/RN-Xcode/Chapters/xc6_release_notes.html under "Xcode 6.3 Release Notes" -> "Swift Language Changes" you find
Swift now detects discrepancies between overloading and overriding in the Swift type system and the effective behavior seen via the Objective-C runtime.

I got the same error due to having having two methods with the same Obj-C signature:
static func prepareForUpSyncing(obj : NSManagedObject!) -> Bool
static func prepareForUpSyncing(objs : [NSManagedObject]!) -> Bool
I didn't want to mark one of them as #nonobjc due to possibility of unforseen consequences at runtime. (Someone can correct me if there is no possibility)
Resolved it by using Swift's external parameter name feature (I made external name same as local name) to the second method, which effectively changes the Obj-c method signature:
static func prepareForUpSyncing(objs objs : [NSManagedObject]!) -> Bool {

Related

Objective-C method that returns a block is not available in Swift

I'm building an Objective-C library that must be compatible with Swift, and I'm having an issue with several methods that return Objective-C blocks being unavailable in Swift even though the interface is being generated in Swift.
An example of a method that has this issue is:
+ (SDLLogFilterBlock)filterByDisallowingString:(NSString *)string caseSensitive:(BOOL)caseSensitive;
which is being generated in Swift as:
open class func filter(byDisallowingString string: String, caseSensitive: Bool) -> __ObjC.SDLLogFilterBlock
SDLLogFilterBlock is defined as:
typedef BOOL (^SDLLogFilterBlock)(SDLLogModel *log);
which is being generated in Swift as:
public typealias SDLLogFilterBlock = (SDLLogModel) -> Bool
When I'm attempting to use the SDLLogFilter class in Swift, however, there is no autocompletion appearing for any method like this and attempting to write it out manually tells me that this method does not exist.
Does Swift 3 not work with generated methods that return a block?

What does this function do "override func `self`() -> Self"?

I am reading AWS SDK sample code on GitHub and saw these following two functions:
// MARK: NSObjectProtocol hack
override func isEqual(object: AnyObject?) -> Bool {
return super.isEqual(object)
}
override func `self`() -> Self {
return self
}
This is only one comment above "NSObjectProtocol hack", which doesn't really make sense to me. Could anyone explain what they are trying to do here?
This is a legacy code you can ignore when using the latest Swift. The earlier versions of Swift had issues recognizing that your mapper object indirectly inherits from NSObject and implements NSObjectProtocol. The current version of Swift does not have the issue, so you can safely ignore these two methods.
This is an example of using a keyword as an identifier. You have to place backtick marks before and after the keyword to use it as such. According to Apple's documentation (under the Identifiers section)
To use a reserved word as an identifier, put a backtick (`) before and after it. For example, class is not a valid identifier, but `class` is valid. The backticks are not considered part of the identifier; `x` and x have the same meaning.
The // MARK: NSObjectProtocol hack is used for commenting a section of code that allows Xcode to format the list of properties/methods etc. into groups.

Swift Protocol compilation error when using TARGET_INTERFACE_BUILDER

I am trying to generate sample data for an #IBDesignable control, so when building for IB I'm fooling the control into being its own datasource. The upshot is I'm adding some methods to a protocol only for use by IB, and as a good citizen I wish to remove these for a regular (non-IB build).
I've distilled my problem down to the following code fragment. My protocol looks like this:-
protocol TestProtocol {
#if TARGET_INTERFACE_BUILDER
func myControl(control:AnyObject, colorForIndex index:UInt) -> UIColor?
func myControl(control:AnyObject, textForIndex index:UInt) -> String?
#endif
}
This fails to compile, with a message that implies an method overloading error: "error: declaration conflicts with previous value". The error message is on the second function declaration, and refers to the first function as the previous declaration it's clashing with.
But these are not overloads, they have different signatures because of the named parameters. And this is such a standard delegate naming convention across Cocoa that I was resistant to renaming my methods without understanding why.
Removing the #if TARGET_INTERFACE_BUILDER fixes the problem, so it is no longer a pressing issue for me, but I am completely stumped as to why adding this conditional compilation would produce such a bizarre error?
I am not sure why it happens, but happen to find a reasonable workaround.
Just separate the two declarations as shown below:
protocol TestProtocol {
#if TARGET_INTERFACE_BUILDER
func myControl(control:AnyObject, colorForIndex index:UInt) -> UIColor?
#endif
#if TARGET_INTERFACE_BUILDER
func myControl(control:AnyObject, textForIndex index:UInt) -> String?
#endif
}

Swift Segmentation Fault with Non-Adoption of Extension

If I have a protocol, MyProtocol defined as:
protocol MyProtocol {
func myFunction() -> String
}
and I have a default implementation declared in an extension so that conformers can "optionally" implement the function:
extension MyProtocol {
func myFunction() -> String { return "" }
}
everything should work just dandy.
However, when a class conforms to that protocol and doesn't implement the functions, the compiler fails with Segmentation fault 11. Once the class implements the function, the error goes away and all is good with the world but it seems to defeat the purpose of defining default implementations in extensions.
Does anyone have any idea why this happens? Is it because the conforming class declares that it implements the methods so the compiler ignores what's written in the extension, can't find the methods and then crashes?
I also had a similar problem with protocol extensions and Segmentation fault 11.
In my case the problem was, that in the extension I put the mutating keyword before the function, but in the protocol there was no mutating. And instead on an error this lead to that Segmentation fault 11.
Maybe that helps a bit.

"fatal error: unavailable function can't be called"

So I just downloaded Xcode 7 GM, and out pops this error:
fatal error: unavailable function can't be called: file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-700.0.59/src/swift/stdlib/public/core/RangeReplaceableCollectionType.swift, line 329
Any ideas on how to resolve this?
Turns out, I had a protocol with the function extend as a requirement.
public protocol Appendable: Initiable, SequenceType
{
mutating func insert(_: Generator.Element)
mutating func append(_: Generator.Element)
mutating func extend<S: SequenceType where S.Generator.Element == Generator.Element>(_: S)
}
Now extend has been renamed to appendContentsOf, however Xcode stayed shush when it came to my protocol requiring it (a bug). Whenever I called extend on conformant types (in my case Array, Dictionary and Set), instead of telling me that extend had been renamed, it just resolved the issue by using a function guaranteed by Appendable, also extend. And guess who provided the implementation.
That's right.
PS: I ran the migrator before doing all of this, and it should have resolved this issue, but eh.

Resources