Isfirstresponder swift issue - ios

I get a "Method does not override any method from its superclass" for a is first responder function. I looked this up online and theres no solution. could you please help me fix this. Here is the code.
public override func isFirstResponder() -> Bool {
// Return true if any of `self`'s subviews is the current first responder.
// Needs to unwrap the IBOutlets otherwise IBInspectable is crashing when using CardTextField because IBOutlets
// are not initialized yet when IBInspectable engine runs.
guard let numberInputTextField = numberInputTextField, let monthTextField = monthTextField, let yearTextField = yearTextField, let cvcTextField = cvcTextField else {
return false
}
return [numberInputTextField, monthTextField, yearTextField, cvcTextField]
.filter({$0.isFirstResponder})
.isEmpty == false
}
Here is an image of the error
Error of IsFirstResponderError

Try to replace this:
public override func isFirstResponder() -> Bool {
with this:
public override var isFirstResponder: Bool {
Apple doc

Related

Swift property nil outside unwindToViewController

To pass data between views, I decided to use a "temporary" object that would act as the data model of my views.
var tempMedecine = TempMedecine()
var xValue = 0
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let dmController = segue.destinationViewController as? JRBDosageMainTableViewController {
dmController.tempMedecine = self.tempMedecine
}
}
#IBAction func unwindToViewController(segue: UIStoryboardSegue) {
if let dosageController = segue.sourceViewController as? JRBDosageMainTableViewController {
self.tempMedecine = dosageController.tempMedecine!
self.xValue = 10
let dosageCell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: 1, inSection: 0))
dosageCell?.detailTextLabel?.text = String(self.tempMedecine.dosageQuantity!) + " " + self.tempMedecine.dosageQuantityType!
}
}
override func shouldPerformSegueWithIdentifier(identifier: String, sender: AnyObject?) -> Bool {
if identifier == "saveMedecine" {
print(xValue)
guard tempMedecine.name != nil else {
Common.genericAlertController(self, title: "Error", message: "You need to define a name", preferedStyle: .Alert)
return false
}
guard self.tempMedecine.dosageQuantityType != nil else {
Common.genericAlertController(self, title: "Error", message: "You need to set a quantity", preferedStyle: .Alert)
return false
}
}
else {
return true
}
return false
}
This is some of my code from the "index" viewController where I need to tackle validation.
As you can see all of my viewControllers have a property named tempMedecine. I pass it around and update the data if needed.
The problem is that self.tempMedecine.dosageQuantityType returns nil in the shouldPerformSegueWithIdentifier method but isn't returning nil in the unwindToViewController method.
I figured there could be two instances of my TempMedecine object, but that's not the case. I also thought there might be a problem with the way I pass the tempMedecine variable between my viewControllers but the property tempMedecine.name is effectively transfered, the only difference is that this property is set in the same viewController where I want to implement validation :
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
self.tempMedecine.name = textField.text
return true
}
It's really looking like I'm working with two different scope. As soon as I leave the unwindToViewController method, I would get back to another scope where the tempMedecine variable isn't updated.
But the weird part is when I use a simple variable like xValue. If I update its value in the unwindToViewController method I get the correct value in shouldPerformSegueWithIdentifier
What am I missing? Thanks for your help.
Okay, I fixed it. What happened was that I implemented some code to reset the dataSource which is tempMedecine if the user decided to click on the Back Button in the navigation bar :
if self.isMovingToParentViewController() {
tempMedecine?.dosageQuantity = nil
tempMedecine?.dosageQuantityType = nil
}
The thing is, I never thought the issue could come from this as I can use the tempMedecine data to set the value in my tableView after unwinding to the index viewController but I totally missed the part when object are passed my reference.

Binding dose not seem to be working from ReactiveCocoa Swift

var viewModel = CTCViewModel()
var mainView: CTCMainView {
return self.view as! CTCMainView
}
override func viewDidLoad() {
super.viewDidLoad()
let callButtonEnabledSignal = self.viewModel.rac_valuesForKeyPath("callButtonEnabled", observer: self.viewModel)
callButtonEnabledSignal.setKeyPath("enabled", onObject: self.mainView.callButton, nilValue: false)
self.mainView.callButton.rac_signalForControlEvents(UIControlEvents.TouchUpInside).subscribeNext {
(Void) -> Void in
self.viewModel.callButtonEnabled = !self.viewModel.callButtonEnabled
}
}
When I press the button, self.viewModel.callButtonEnabled did get updated but the enabled property of the button. It does not seem they are bound.
Add dynamic on your callButtonEnabled property:
class CTCViewModel: NSObject {
dynamic var callButtonEnabled = false
}
Because the implementation of rac_valuesForKeyPath is using Objective-C runtime, and the compiler can omit it when access Swift properties. You mark a property with dynamic to let the compiler always use Objective-C runtime.

Swift: Unable to set property value on mutable object paramter

I have the following code:
func enableDelaysContentTouchesIncudlingSubviews(enable: Bool) {
self.setDelaysContentTouches(enable, forObject: self)
for obj: AnyObject in self.subviews {
self.setDelaysContentTouches(enable, forObject: obj)
}
}
private func setDelaysContentTouches(var value: Bool, var forObject obj: AnyObject) {
if obj.respondsToSelector("setDelaysContentTouches:") {
obj.delaysContentTouches = value
}
}
On the second function, the line obj.delaysContentTouches = value raises the following error: Cannot assign to property: 'obj' is immutable
I don't understand the reason since obj is declared as a var parameter. Therefor it should be mutable in my understanding.
Could somebody please explain me the reason and also provide a workaround.
Thanks in advance!
My guess is it's an issue of AnyObject technically being a protocol
Assuming you're working in a view, maybe try something along these lines:
func enableDelaysContentTouchesIncudlingSubviews(enable: Bool) {
self.setDelaysContentTouches(enable, view: self)
self.subviews.forEach({setDelaysContentTouches(enable, view: $0)})
}
private func setDelaysContentTouches(enable: Bool, view: UIView) {
if let viewAsScrollview = view as? UIScrollView {
viewAsScrollview.delaysContentTouches = enable;
}
}
This is a much swiftier way of doing things, more clear, and doesn't use "respondsToSelector"
More info, and possibly a more direct answer about respondsToSelector in swift here

Is there any way to have a subclass's override method return when a guard block on the super class is invoked

Currently I have a super class:
class ShareButtonAction : ButtonAction {
override func execute() {
guard let isReachable = reachability?.isReachable() where isReachable == true else {
print("No network connection")
return
}
}
And a child class of ShareButtonAction:
class ShareTwitterAction : ShareButtonAction {
override func execute() {
super.execute()
guard let isReachable = reachability?.isReachable() where isReachable == true else {
return
}
}
I don't want the child class's implementation of execute to be fired off if the guard condition is caught in the superclass. Currently I have to duplicate code which is bothering me.
Is there a way to tell the child class dont bother executing if the superclass guard is caught.
I know I can fall back to passing blocks and not execute the containing block of the guard fails although I feel like there should be a built in mechanism in swift to make this easier. I am hoping I just have not found it yet.
You could make the method return a boolean value and use that to decide if you want to execute the code in the subclass.
class ShareButtonAction : ButtonAction {
override func execute() -> Bool {
guard let isReachable = reachability?.isReachable() where isReachable else {
print("No network connection")
return false
}
return true
}
}
class ShareTwitterAction : ShareButtonAction {
override func execute() -> Bool {
let result = super.execute()
if result {
//... your code here
}
return result
}
}
The built-in mechanisms are either returning a value from the superclass implementation, or throwing an exception there. In a simple case, have the method return a boolean value. The subclass implementation can check the return value from the superclass call.

SFSafariViewController: how to provide custom activities?

The WWDC session of Safari View Controller mentioned that apps could provide custom activities through the method func safariViewController(controller: SFSafariViewController, activityItemsForURL URL: NSURL, title: String?) -> [UIActivity] of the delegate SFSafariViewControllerDelegate. I have tried to implement this method, but it is not called after I present the SFSafariViewCntroller. I also implemented another optional method of that delegate, func safariViewControllerDidFinish(_: SFSafariViewController), which does get called. I tried to add the "#objc" keyword to my method (required by some other protocols), but it seems not to change anything.
I am wondering what could go wrong.
Thanks!
Here's the example code for your reference. In your main view:
func safariViewController(controler: SFSafariViewController, activityItemsForURL: NSURL, title: String?) -> [UIActivity] {
//global variable for the url to be shared
webPageUrl = activityItemsForURL.absoluteString
//global variable for the title to be shared
webPageTitle = title!
let wcActivity = WeChatActivity()
let wcMoment = WeChatMoment()
return [wcActivity, wcMoment]
}
Custom activities 1
import UIKit
class WeChatActivity : UIActivity{
override init() {
self.text = ""
}
var text:String?
override func activityType()-> String {
return "WeChat"
}
override func activityImage()-> UIImage?
{
return UIImage(named: "WeChat")!
}
override func activityTitle() -> String
{
return "微信好友"
}
override class func activityCategory() -> UIActivityCategory{
return UIActivityCategory.Action
//you can change to .Share and it'll appear in the share line
}
func getURLFromMessage(message:String)-> NSURL
{
var url = "whatsapp://"
if (message != "")
{
url = "\(url)send?text=\(message)"
}
return NSURL(string: url)!
}
override func canPerformWithActivityItems(activityItems: [AnyObject]) -> Bool {
return true;
}
override func performActivity() {
shareToWeChat("ftcweixin://?url=\(webPageUrl)&title=\(webPageTitle)&description=\(webPageDescription)&img=\(webPageImageIcon)&to=chat")
}
}
Custom Activity 2:
import UIKit
class WeChatMoment : UIActivity{
override init() {
self.text = ""
}
var text:String?
override func activityType()-> String {
return "WeChatMoment"
}
override func activityImage()-> UIImage?
{
return UIImage(named: "Moment")!
}
override func activityTitle() -> String
{
return "微信朋友圈"
}
override class func activityCategory() -> UIActivityCategory{
return UIActivityCategory.Action
}
func getURLFromMessage(message:String)-> NSURL
{
var url = "whatsapp://"
if (message != "")
{
url = "\(url)send?text=\(message)"
}
return NSURL(string: url)!
}
override func canPerformWithActivityItems(activityItems: [AnyObject]) -> Bool {
return true;
}
override func performActivity() {
shareToWeChat("ftcweixin://?url=\(webPageUrl)&title=\(webPageTitle)&description=\(webPageDescription)&img=\(webPageImageIcon)&to=moment")
}
}
You'll be able to see the two new icons in the action line of the action sheet. You can also change it to appear in the share line, as explained in the code.
One final note, there are pitfalls for WeChat sharing on Safari View, as WeChat doesn't conform to Safari's sharing standard. You can click the WeChat Share icon and WeChat will be able to share. But you can only get the page title and url in Safari View's page, unlike with WKWebView where you can get everything using evaluateJavaScript. So you'll need to get the share image and description (for sharing to friends) from other places.

Resources