I've just migrated my code to Swift 4 and it added in lots of #objc code infront of several functions.
I think I get why after reading lots of posts on here, but my question is this - is there an alternative way of writing this code, that doesn't need to expose the Objective C runtime?
For example:
#objc func textFieldDidChange(textField: UITextField) {
checkCode(textField.text ?? "")
}
Or:
#objc func hideKeyboard() {
commentsBox.resignFirstResponder()
}
Or:
#objc func setDateChanged(_ sender:UIDatePicker) {
setDate.text = dateFormatter.string(from: sender.date)
}
Is there a different way to write this code, that doesn't involve the #objc bit at the start?
Why? I like shorter, cleaner code (which is why I love Swift).
Many thanks in advance!
Related
I faced an issue which is pretty interesting for me. Probably you have better explanation and I would like share and discuss a little bit.
protocol HomeViewModelProtocol {
func getText(postCode: String?)
}
ViewModel
HomeViewModel: HomeViewModelProtocol {
func getText(postCode: String?) {
guard let postCode = postCode else {
return
}
postCode = someLocalVariable
}
View
postCodeTextField.addTarget(self, action: #selector(postCodeFieldDidChange(_:)), for: .editingChanged)
#objc private func postCodeFieldDidChange(_ textField: UITextField) {
viewModel.getText(postCode: textField.text)
}
I am simply view and viewmodel. I want to pass optional type to viewmodel because i thought it would be better handling optional binding in view model ( view should not handle any logic ) am I right ?
But i feel like this is strange, I never see such approach before and probably i am making some mistake that is why I want to ask how can handle this getText better meaningful and elegance according to SOLID.
IMO everything is clear so please try to understand a little bit before closing the question if you think it is need debug details
Thanks
Makes no sense. The property text of UITextField ā although declared as optional ā is never nil. You can force unwrap it
#objc private func postCodeFieldDidChange(_ textField: UITextField) {
viewModel.getText(postCode: textField.text!)
}
or in case of Exclamationmarkophobia use the nil-coalescing operator
#objc private func postCodeFieldDidChange(_ textField: UITextField) {
viewModel.getText(postCode: textField.text ?? "")
}
and declare your protocol method non-optional.
protocol HomeViewModelProtocol {
func getText(postCode: String)
}
I am currently learning swift 5.2 and I found a problem when I try to use #selector and #objc function.
I created a #objc function and I call it in the #selector, but the function has a strikethrough in the autofill. Just like some other functions that is deprecated. It doesn't really affect anything, the app work just fine. But I really want to know why the strikethrough appears.
Someone says that is because the function recommend a return value. And I tried to return something, like a Bool, in the #objc function. And the strikethrough is gone, but it still affect nothing, no matter what the function returns.
This really confused me. Is there any one who can tell me why? Thanks!
Here is my minimal reproducible example:
let refreshControl_A = UIRefreshControl()
let refreshControl_B = UIRefreshControl()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
refreshControl_A.addTarget(self, action: #selector(refresh_A(sender:)), for: .valueChanged)
refreshControl_B.addTarget(self, action: #selector(refresh_B(sender:)), for: .valueChanged)
}
#objc func refresh_A(sender: UIRefreshControl) {
print("Have strikethrough!")
}
#objc func refresh_B(sender: UIRefreshControl) -> Bool {
print("No strikethrough!")
return true
}
The refresh_A function has the strikethrough in the autofill.
But the refresh_B function doesn't have the strikethrough in the autofill.
The only difference between these two functions is the return type, one is Viod, and the other is Bool. Both functions work fine.
Can anyone help me out with this error? Not sure what it's asking for...
TapGestureRecognizer Syntax
override func viewDidLoad() {
super.viewDidLoad()
let tapStart = UITapGestureRecognizer(target: self, action:#selector(tapped(gesture:)))
self.view.addGestureRecognizer(tapStart)
func tapped(gesture: UITapGestureRecognizer){
print("It actually worked")
}
}
my end goal seems like it should be fairly simple:
I want to segue to another view when the user taps anywhere on the screen. I'm creating a TapGestureRecognizer and for now am simply printing to the logs as the method so I can easily see if it works.
Thanks!
Try using #selector(tapped(gesture:)) if you're on Swift 3. If you're on Swift 2 the selector will probably be tapped(_:) or something instead.
The compiler will ensure the existence of the symbol you're referencing when you use #selector. If you use a string and let the compiler create a Selector from the string literal, all you get is a warning like this. Same disadvantage goes for using the Selector("funcname") constructor.
Try this code: Tested in Swift 3
Note: Syntax changed in Swift 3.
You can auto fix by holding function+control+option+command+f on your keyboard then Xcode will fix the issue for you.
Is nothing wrong with your code.Just, The way you using it.You,should placing your code like this...
override func viewDidLoad() {
super.viewDidLoad()
let tapStart = UITapGestureRecognizer(target: self, action:#selector(tapped(gesture:)))
self.view.addGestureRecognizer(tapStart)
}
func tapped(gesture: UITapGestureRecognizer){ // func tapped(_:) this will works to
print("Your in Right track mate")
}
I've tried looking at other StackOverflow inquires about this, I can't seem to find the solution to this. I'm not sure if this is due to me looking at threads which are non-Swift 2.0.
I will need NSNotification to pass any kind of value to my Main View Controller. But I keep getting:
Optional(foobar)
Here's a function on View Controller B:
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
let notificationName = "CoreLocationNSN"
let notification = NSNotification(name: notificationName, object: self, userInfo: ["doge":"foobar"])
NSNotificationCenter.defaultCenter().postNotification(notification)
}
Here's my main View Controller's initialization function:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
NSNotificationCenter.defaultCenter().addObserver(self, selector: "testNSNWithObject:", name: CoreLocationNSN, object: nil)
}
func testNSNWithObject(notification: NSNotification) {
print("Printing...")
print(String(notification.userInfo!["doge"]))
print(String(notification.userInfo?["doge"]))
print(notification.userInfo!["doge"])
print(notification.userInfo?["doge"])
}
But, here's my output:
Printing...
Optional(foobar)
Optional(foobar)
Optional(foobar)
Optional(foobar)
You just need to unwrap the String
func testNSNWithObject(notification: NSNotification) {
if let dodge = notification.userInfo?["dodge"] as? String {
print(dodge)
}
}
I suggest you to avoid the force unwrap operator ! since it's dangerous and there are several safer solutions available in Swift.
I've solved it, looks like it can be unwrapped by adding ! at the end, for some reason I thought my compiler was yelling at me for doing so:
func testNSNWithObject(notification: NSNotification) {
print("Printing...")
print(String(notification.userInfo!["doge"]))
print(String(notification.userInfo?["doge"]))
print(notification.userInfo!["doge"]!) // <<-- THIS ONE WORKED!
print(notification.userInfo?["doge"]!)
}
Just going to keep this here since this issue has been troublesome for me in the past and the syntax seems very strange.
Does anyone know what else I could have done instead that would've removed the "Optional()" from the string?
Here is my AppDelegate.swift. I implement the applicationShouldTerminate protocol from NSApplication. Which answer I give depends on the status of is.Started in the mainWindowController. (This is the SpeakLine example from Cocoa Programming for OS X: The Big Nerd Ranch Guide 5/eāI'm trying to take the example one step further and keep the program from being allowed to quit while the talking is going on.)
What I want to do is change TerminateReply.TerminateCancel to TerminateReply.TermianteLater and then send NSApplication the replyToApplicationShouldTerminate(true) signal when the talking is done. As it stands now in the MainControllerWindow.swift class I have a function set up to handle state changes in the Speech Synthesizer and that's where I want to call it.
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
var mainWindowController: MainWindowController?
func applicationDidFinishLaunching(aNotification: NSNotification) {
let mainWindowController = MainWindowController()
mainWindowController.showWindow(self)
self.mainWindowController = mainWindowController
}
func applicationShouldTerminate(sender: NSApplication) -> NSApplicationTerminateReply {
if (mainWindowController!.isStarted) {
return NSApplicationTerminateReply.TerminateCancel
} else {
return NSApplicationTerminateReply.TerminateNow
}
}
}
The trouble is, when I put it here, I get an error.
var isStarted: Bool = false {
didSet {
updateButtons()
NSApplication.replyToApplicationShouldTerminate(true)
}
}
it tells me I can't use a bool. It also tells me I can't use an Objective C bool when I try to put YES. How do I tell NSApplication it's OK to quit now?
I believe you should change
NSApplication.replyToApplicationShouldTerminate(true)
to
NSApplication.sharedApplication().replyToApplicationShouldTerminate(true)
since replyToApplicationShouldTerminate is a instance method rather then a class method.
my tow cents for swift 5.x:
NSApplication.shared.reply(toApplicationShouldTerminate: true)