Could somebody explain to me how I can set acceptsFirstResponder on a NSViewController in Swift and xcode 6?
The program doesn't allow any overriding of the function and says it doesn't exist in the superclass but I can also not set it as a variable like:
self.acceptsFirstResponder = true
Anybody know?
I had a similar issue but with a NSView Class. I was able to make this work with the following. I had to put it in the class outside any functions.
import Cocoa
class MyView: NSView, NSDraggingDestination {
//MARK: Variables
override var acceptsFirstResponder: Bool { return true }
override var opaque: Bool { return true }
var bgColor : NSColor = .yellowColor()
var lastString : String = ""
var attributes : NSMutableDictionary = [:]
var highlightNeeded = false
Related
I am using a Swift class which uses a variable sharedInstance. When I am trying to use this variable in my Objective-C file, I am getting the error:
No known class method for selector 'sharedInstance'
My Swift class:
class SpeakToMeForUnity : NSObject, SFSpeechRecognizerDelegate {
fileprivate var speechRecognizer : SFSpeechRecognizer?
fileprivate var recognitionRequest : SFSpeechAudioBufferRecognitionRequest?
fileprivate var recognitionTask : SFSpeechRecognitionTask?
fileprivate var audioEngine : AVAudioEngine?
static let sharedInstance = SpeakToMeForUnity()
override fileprivate init() {
super.init()
self.speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "ja-JP"))!
self.audioEngine = AVAudioEngine()
self.speechRecognizer?.delegate = self
}
// Some other functions
}
Below is my Objective-C file:
#import <Speech/Speech.h>
#import "SpeakToMeForUnity-Swift.h"
extern "C"
{
void _prepareRecording()
{
SpeakToMeForUnity *instance = [SpeakToMeForUnity sharedInstance];
[instance prepareRecording];
}
void _recordButtonTapped()
{
SpeakToMeForUnity *instance = [SpeakToMeForUnity sharedInstance];
[instance recordButtonTapped];
}
}
I am using Swift 4 and Xcode 10.3.
Normally to make Swift available in Objective-C you just need to import your swift module #import "ProductModuleName-Swift.h", as you're doing.
If you need the swift code in the Objective-C header use #class MySwiftClass; or #protocol MySwiftClass;.
You can force some class or property to be accessible in Objective-C by adding the attribute #objc.
Remember that private or fileprivate access level attributes will not be accessible unless you add the previous attribute.
To expose things to ObjC, you need to mark them #objc. In this case you should add this before class and before the static let.
In previous versions of Swift, inheritance from NSObject automatically implied #objc, but that was removed, and it now needs to be explicit.
To Get the rootViewController in Objective-c you can use the below line of code
[[[UIApplication sharedApplication] delegate] window].rootViewController
I tried to do the same in swift
UIApplication.sharedApplication().delegate?.window?.rootViewController
But I got this error
'UIWindow?' does not have a member named 'rootViewController'
And the suggestion says that you have to unwrap UIWindow twice UIWindow?? to be
UIApplication.sharedApplication().delegate?.window??.rootViewController
My Question is: Why do I need to unwrap the window twice ?
.
.
I have looked in the API and found that
protocol UIApplicationDelegate : NSObjectProtocol {
optional var window: UIWindow? { get set }
}
The window has one optional
class UIWindow : UIView {
var rootViewController: UIViewController?
}
Also the rootViewController has one optional
.
.
I thought may be because UIWindow in UIApplicationDelegate protocol has optional and UIWindow? so I tried the below in Playground
#objc protocol MyApplicationDelegate {
optional var myWindow: MyWindow? { get set }
}
class MyWindow : NSObject {
var rootViewController: Int?
init(number: Int) {
rootViewController = number
}
}
class MyAppDelegate: MyApplicationDelegate {
var myWindow: MyWindow?
init() {
myWindow = MyWindow(number: 5)
}
}
let myDelegate = MyAppDelegate()
println(myDelegate.myWindow?.rootViewController)
However I can get myWindow with one optional and can successfully log '5'
What am I missing here?
Well; I found the problem with my example
In my example I'm creating object from MyAppDelegate directly which will sure have myWindow property as I'm defining it
Changing the example to be the following
#objc protocol MyApplicationDelegate {
optional var myWindow: MyWindow? { get set }
}
class MyWindow : NSObject {
var rootViewController: Int?
init(number: Int) {
rootViewController = number
}
}
class MyAppDelegate: MyApplicationDelegate {
var myWindow: MyWindow?
init() {
myWindow = MyWindow(number: 5)
}
}
class MyApplication: NSObject {
var myDelegate: MyApplicationDelegate
override init() {
myDelegate = MyAppDelegate()
}
}
let myApplication = MyApplication()
println(myApplication.myDelegate.myWindow??.rootViewController)
I needed to add another class MyApplication that has a property conform toMyApplicationDelegate
So I was able to use myWindow?? first unwrapping for the optional part in the protocol and second one is for the optional declaration in the variable UIWindow?
I am trying to switch one of my apps from Objective-C to swift. There are some things in swift language that I can't get to work. First of all, I have a Model class which I initialise in AppDelegate's didFinishLaunchingWithOptions. I declare the Model's object in the .h file in Objective-C like this:
#property(nonatomic,retain)Model *model;
The in the didFinishLaunchingWithOptions I initialise it:
self.model=[[Model alloc]init];
And then I have the following method:
+(Model *)getCurrentModel{
AppDelegate *appdelegate=(AppDelegate *)[UIApplication sharedApplication].delegate;
return appdelegate.model;
}
And then I can access the current instance of Model from any class by calling:
model = [AppDelegate getCurrentModel];
So, the first question, how can I do the same in Swift? Especially the static functions(the function that begin with +). I tried this:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var model : Model?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
// Override point for customization after application launch.
model = Model()
return true
}
class var currentModel : Model {
struct Static {
static let instance : Model = AppDelegate.sharedApplication.delegate //error AppDelegate.Type does not have a member named sharedApplication
}
return Static.instance.model
}
Second question. In Objective C, we can make an instance variable and global variable and global function by declaring in.h file like this:
#interface ViewController : UIViewController {
//Instance Variables
NSString *aName;
}
//Properties or variables that can be accessed globally
NSString *anotherName;
//Methods that have global scope
- (void)doSomething;
#end
Those functions that are not declared in the .h file have a local scope. How do I do the same in Swift?
sharedApplication is a method of UIApplication, not of AppDelegate.
In addition, you have to unwrap the optional for then return value:
class var currentModel : Model {
struct Static {
static let instance = UIApplication.sharedApplication().delegate as AppDelegate
}
return Static.instance.model!
}
Some small steps to begin wrapping my head around Swift. I've basically ported an old class that simply finds the matching icon for a name and return the appropriate UIImage. The Swift part of things seems to be up and running, and looks (almost) like this:
#objc class ImageHandler{
func iconForData(data: MyData) -> UIImage{
let imagesAndNames = [
"1": "tree.png",
"2": "car.png",
"3": "house.png",
"7": "boat.png",
]
var imageName: String? = imagesAndNames[data.imageName]
if !imageName{
imageName = "placeholder.png"
}
let icon = UIImage(named: imageName)
return icon
}
}
There are no warnings on the above. My old Objective-C class is however asking for an alloc method on the swift class.
ImageHandler *imageHandler = [ImageHandler alloc] init];
Returns the error "No known class method for selector 'alloc' which is true enough I guess, but how do I escape this? Will I have to base my swift-class of NSObject to avoid this?
You declare your ImageHandler class as a root class. It doesn't have alloc method itself. You need to inherit from NSObject:
#objc class ImageHandler : NSObject {
...
}
Referenced from this ADF thread.
Just wanted to comment here that if you don't want to subclass NSObject or any other ObjC object, you can declare a class level initializer:
#objc class ImageHandler{
class func newInstance() -> ImageHandler {
return ImageHandler()
}
func iconForData(data: MyData) -> UIImage{
let imagesAndNames = [
"1": "tree.png",
"2": "car.png",
"3": "house.png",
"7": "boat.png",
]
var imageName: String? = imagesAndNames[data.imageName]
if !imageName{
imageName = "placeholder.png"
}
let icon = UIImage(named: imageName)
return icon
}
}
Then in ObjC
ImageHandler * imageHandler = [ImageHandler newInstance];
This way, you don't have to be dependent on ObjC Class inheritance unless you want to.
This answer is if you want to keep using pure swift objects, and do not want to inherit from NSObject. If you don't care about using pure swift objects then use akashivskyy's answer above.
I came across this same issue. I took Logan's answer and modified it so that the Objective-C caller does not have to change behavior. This is especially important if you are doing like I am and building a framework that could be consumed by Objective-C or Swift projects.
#objc public class TestClass {
public init(){}
public class func alloc() -> TestClass {return TestClass()}
}
The Objective-C implementation gets to stay familiar.
TestClass *testClass = [[TestClass alloc] init];
Swift implementation stays the same as well.
let testClass = TestClass()
Edit:
Furthermore I went on to implement this into an class that can be subclassed by other pure swift objects.
#objc public class ObjectiveCCompatibleObject {
required public init(){}
public class func alloc() -> Self {return self()}
}
If we want to import swift file in Objective C, Should do
import "productname-Swift.h" or use angular brackets <>
in Objective C file. Then can access alloc, init for specific imported swift class in Objective C.
You could do this:
ImageHandler *imageHandler =
[[NSClassFromString(#"YourProjectName.ImageHandler") alloc] init];
(or, if you had done #objc(ImageHandler) class ImageHandler in Swift, you would do [[NSClassFromString(#"ImageHandler") alloc] init])
Alternately, you can declare (but not implement) a dummy category containing the alloc method at the top of your Objective-C file:
#interface ImageHandler (Dummy)
+ (instancetype)alloc;
#end
And then you can directly use it in your code:
ImageHandler *imageHandler = [[ImageHandler alloc] init];
I have some code that I would like to run only once in my MainViewController. It should run every time the user starts the app, but only after the MainViewController has loaded.
I don't want to run it in -(void)applicationDidFinishLaunching:(UIApplication *)application.
Here's the idea I had:
MainViewController.h
#interface IpadMainViewController : UIViewController <UISplitViewControllerDelegate> {
BOOL hasRun;
}
#property (nonatomic, assign) BOOL hasRun;
MainViewController.m
#synthesize hasRun;
-(void)viewDidLoad {
[super viewDidLoad];
if (hasRun == 0) {
// Do some stuff
hasRun = 1;
}
}
Any ideas?
Swift 1,2:
static var token: dispatch_once_t = 0
dispatch_once(&token) {
NSLog("Do it once")
}
Objective-C
static dispatch_once_t once;
dispatch_once(&once, ^ {
NSLog(#"Do it once");
});
Swift 3,4:
dispatch_once is no longer available in Swift. In Swift, you can use
lazily initialized globals or static properties and get the same
thread-safety and called-once guarantees as dispatch_once provided
Apple doc
let myGlobal = { … global contains initialization in a call to a closure … }()
_ = myGlobal // using myGlobal will invoke
// the initialization code only the first time it is used.
I don't see any problem with that code. I like using a BOOL (as you did) and then assigning either YES/NO or TRUE/FALSE just so that the code reads more nicely. I would assign TRUE to firstRun in didFinishLaunching, and set it FALSE after the code executes. In my code these type of conditionals usually look like this:
#synthesize firstRun;
-(void)viewDidLoad {
[super viewDidLoad];
if (firstRun) {
// code to run only once goes here
firstRun = FALSE;
}
}
Possible variation (Swift 5):
// Whether this is the first code run since app (re)started
var firstRun: Bool = true
public final class Foo {
public init() {
if firstRun {
// Code that has to be run only once goes
// HERE
firstRun = false
}
}
}
Since there is no dispatch_once_t ins swift 3 and above, we can use lazy initialized global variables.
Make a lazy global variable
lazy var doOnlyOnce: () -> Void = {
.. add code to run only once here ..
return {}
}()
To run the code:
_ = doOnlyOnce
With Swift2.0, Xcode 7.0
var token: dispatch_once_t = 0
override func viewDidLoad() {
super. viewDidLoad()
dispatch_once(&token) {
println("This is printed only on the first call to test()")
}
println("This is printed for each call to test()")
}
for Swift2.2,Xcode 7.3:
static var token: dispatch_once_t = 0
dispatch_once(&YourClassName.token) {
NSLog("Do it once")
}
Watch out "YourClassName.token"