I just upgraded from swift 2 to swift 3 and I am running into some problems with overriding a property.
In swift 2 you could set the activity type like this
override func activityType() -> String? {
return "com.a.string"
}
However in swift 3 (in Xcode 8 beta 6) they introduced NS_STRING_ENUM and now we override activityType like this
override var activityType() -> UIActivityType? {
return UIActivityType.customActivityType
}
The problem is that Xcode will complain with this:
Property cannot be an #objc override because its type cannot be represented in Objective-C
One solution i found is to add the annotation #nonobjc to it like so:
#nonobjc override var activityType() -> UIActivityType? {
return UIActivityType.customActivityType
}
While this helps make the error go away, this property never gets called...
This is a problem because when the user completes the activity and completionWithItemsHandler() gets called, the activity type is considered nil.
One work around I found is to use an objective-c extension. It works; it gives me type "horse" like I wanted.
#interface Custom_UIActivity (custom)
- (UIActivityType)activityType;
#end
#implementation Custom_UIActivity (custom)
- (UIActivityType)activityType {
return #"horses";
}
My question is how to do it in a pure swift.
In pure Swift3 I am able to compile it using
override var activityType: UIActivityType {
return UIActivityType(rawValue: self.customActivityType.rawValue)
}
Related
I'm trying to figure out how to override controlAlternatingRowBackgroundColors in Swift but whatever I do I seem to get an error.
extension NSColor {
class var controlAlternatingRowBackgroundColors: [NSColor] {
return [NSColor.red, NSColor.blue]
}
}
This gives me "Getter for 'controlAlteratingRowBackgroundColors' with Objective-C selector 'controlAlteratingRowBackgroundColors' conflicts with previous declaration with the same Objective-C selector.
If I use override then I get an error saying that it doesn't override anything.
If I create a category on NSColor in objective c it all works as expected!
I have a protocol Reusablethat has a static function static func reuseId() -> String and a protocol extension that defines the default implementation for the function. Then, I implemented a extension on UITableViewCell to conform to the Reusable protocol. I can now use the function on my TableViewCells without a problem: SomeTableViewCell.reuseId().
The Problem I have is with Generics. I have a generic class that has a generic parameter of the type UITableViewCell:
internal class SomeClass<CellType: UITableViewCell>: NSObject {
...
}
I want to be able to use the function specified in Reusable in my generic class on CellType but unfortunately this does not work as expected. The compiler always generates the error Type 'CellType' has no member 'reuseId'.
Does anybody know why this is happening? Is there a workaround?
I am using Xcode 7.0 with Swift 2.0.
Greetings from Germany
UPDATE: Here is some sample code that better shows my problem:
import UIKit
protocol Reusable {
static func reuseId() -> String
}
extension Reusable {
static func reuseId() -> String {
return String(self).componentsSeparatedByString(".").last!
}
}
extension UITableViewCell: Reusable { }
class SomeGenericClass<CellType: UITableViewCell> {
func someFunction() {
let reuseIdentifier = CellType.reuseId()
}
}
This Code will generate the above error but I do not quite understand why this happens. I think the main difference to the sample code that jtbandes posted is that I use a static function.
UPDATE: The issue is fixed in Xcode 8.3 beta 2. The sample code above now works as expected (after migrating it to Swift 3 of course).
That's an interesting problem. Your code seems like it should work; you might want to file an enhancement request.
Here's a workaround that seems to work correctly:
class SomeGenericClass<CellType: Cell> {
func someFunction() {
let reuseIdentifier = (CellType.self as Reusable.Type).reuseId()
}
}
Another (workaround) way to get what you need:
class GenericExample<CellType:UITableViewCell where CellType:Reusable>
{
func test() -> String {
return CellType.reuseId()
}
}
GenericExample<UITableViewCell>().test() // returns "UITableViewCell"
GenericExample<MyCell>().test() // returns "MyCell"
I just updated from swift 1.1 to swift 1.2 and get compiler Error:
Method 'setVacation' redeclares Objective-C method 'setVacation:'
Here some code:
var vacation : Vacation?
func setVacation(_vacation : Vacation)
{...}
But I need call setVacation
Is any suggestions how fix this?
This is cause by the change stated in Xcode 6.3beta release notes:
Swift now detects discrepancies between overloading and overriding in
the Swift type system and the effective behavior seen via the
Objective-C runtime. (18391046, 18383574) For example, the following
conflict between the Objective-C setter for “property” in a class and
the method “setProperty” in its extension is now diagnosed:
class A : NSObject {
var property: String = "Hello" // note: Objective-C method 'setProperty:’
// previously declared by setter for
// 'property’ here
}
extension A {
func setProperty(str: String) { } // error: method ‘setProperty’
// redeclares Objective-C method
//'setProperty:’
}
To fix this you need to make all you method signatures unique (as Objective-C does not provide method overload)
Or don't inherit from NSObject if you need Swift only class.
Cappy: For the Standford problem I used simply this, because it looks like the Xcode Beta simply says that the operation: (Double, Double) -> Double is the same as operation: Double -> Double, I don't know if it is a bug or not...
But the code below works, but is NOT clean :(
func performOperation(r:String? = "2", operation: (Double, Double) -> Double) {
if operandStack.count >= 2 {
displayValue = operation(operandStack.removeLast(), operandStack.removeLast())
enter()
}
}
func performOperation(operation: Double -> Double) {
if operandStack.count >= 1 {
displayValue = operation(operandStack.removeLast())
enter()
}
}
As noted by #Kirsteins, Swift now detects conflicting symbols between Swift and Obj-C, and swift symbols that would cause Obj-C grief. In addition to the answer given, you can avoid this in general by specifying a required label for the additional types, thus changing the call signature:
import Foundation
extension NSObject {
func foo(d:Double, i:Int) { println("\(d), \(i)") }
func foo(withInt d:Int, i:Int) { println("\(d), \(i)") }
}
let no = NSObject()
no.foo(withInt:1, i: 2)
Beyond that though, and to answer your immediate question, you are trying to apply Obj-C idioms to Swift. What you really want, is to either implement didSet (most likely), or possibly set:
class WhatIDidLastSummer {
var vacation:Bool = false {
didSet {
// do something
}
}
var staycation:Bool {
get { return true }
set {
// do something
}
}
}
I have a class, SlideAnimationController, that is a subclass of NSObject should conform to the UIViewControllerAnimatedTransitioning protocol.
In Xcode 6 GM, I get the error message that my class does not conform to the protocol.
I have implemented transitionDuration and animateTransition. These are the only two required methods of the three that the protocol calls for.
Adding the last method, animationEnded, does not make any difference.
What am I missing? This same code was functional not too long ago.
Edit
Here is the class implementation:
import UIKit
class SlideAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
var fromIndex: Int = 0
var toIndex: Int = 0
func transitionDuration(transitionContext: UIViewControllerContextTransitioning!) -> NSTimeInterval {
return 1
}
func animateTransition(transitionContext: UIViewControllerContextTransitioning!) {
//Stuff
}
}
This bug has to do with changes to Swift's versions of Objective-C API's. In many cases where Swift had implicitly unwrapped optionals as arguments, the arguments have been changed to either normal or optional variables.
Normally, when overriding a method, Xcode offers a fix-me to correct these uses of ! where they are no longer needed.
However, since these methods I declared are not necessarily part of the protocol, Xcode recognizes these methods, just does not realize that those are the ones I want for the protocol.
In order to fix this, I needed to remove the !'s from both method parameters (e.g. UIViewControllerContextTransitioning! becomes UIViewControllerContextTransitioning)
i got two swift files :
main.swift and view.swift
In main.swift i have a variable (Int) initially set to 0.
With an IBACtion I set that variable to be 10, and everything is ok.
However, if I try access that variable from view.swift, with a simple call like main().getValue(), i get always 0 and not 10 even if the variable has changed it's value in main.swift.
The method getValue() in main.swift looks like this:
func getValue() -> Int {
return variable
}
EDIT
Here is the code (Translated from Italian :D )
import Cocoa
class Main: NSObject {
var variable: Int = 0
func getValue() -> Int {
return variable
}
#IBAction func updateVar(sender: AnyObject!) {
variable = 10
}
}
class View: NSView {
override func drawRect(dirtyRect: NSRect) {
println(Main().getValue()) //Returns always 0
}
}
Thanks in advance
Alberto
I have solved this by creating a generic main class which is accessible to all views. Create an empty swift file, name it 'global.swift' and include it in your project:
global.swift:
class Main {
var name:String
init(name:String) {
self.name = name
}
}
var mainInstance = Main(name:"My Global Class")
You can now access this mainInstance from all your view controllers and the name will always be "My Global Class". Example from a viewController:
viewController:
override func viewDidLoad() {
super.viewDidLoad()
println("global class is " + mainInstance.name)
}
There is an important distinction to be made between "files" in Swift and "classes". Files do not have anything to do with classes. You can define 1000 classes in one file or 1 class in 1000 files (using extensions). Data is held in instances of classes, not in files themselves.
So now to the problem. By calling Main() you are creating a completely new instance of the Main class that has nothing to do with the instance that you have hooked up to your Xib file. That is why the value comes out as the default.
What you need to do, is find a way to get a reference to the same instance as the one in your Xib. Without knowing more of the architecture of your app, it is hard for me to make a suggestion as to do that.
One thought, is that you can add a reference to your Main instance in your Xib using an IBOutlet in your View. Then you can simply do self.main.getValue() and it will be called on the correct instance.