Call class method with argument from another class method - ios

In my code file MyItemVC.swift I have defined the following class and method:
class MyItemVC: UIViewController, UITextViewDelegate {
var timer = NSTimer()
func cycleTimer(toggleOn: Bool) {
if toggleOn == true {
// Timer calls the replaceItem method every 3 seconds
timer = NSTimer.scheduledTimerWithTimeInterval(3, target: self, selector: Selector("replaceItem"), userInfo: nil, repeats: true)
} else {
timer.invalidate() // stop the timer
}
}
}
Elsewhere in this class, I call cycleTimer(true) to start the timer and cycleTimer(false) to stop it.
Now, I also want to use the usual methods in my AppDelegate.swift code file to start and stop the timer when the app moves from active to inactive state. But I'm having trouble calling the cycleTimer method from that class.
I found an answer on Stack Overflow that suggested I could call it like this:
func applicationWillResignActive(application: UIApplication) {
MyItemVC.cycleTimer()
}
But I also need to pass in an argument. So I tried calling it like this:
func applicationWillResignActive(application: UIApplication) {
MyItemVC.cycleTimer(true)
}
But I got this error:
Cannot invoke 'cycleTimer' with an argument list of type '(Bool)'
How can I call this method from the AppDelegate methods while passing in an argument?
Thanks for the help. I realize this must be a very basic question but I'm new to programming and trying to teach myself using Swift. An answer using Swift rather than Obj-C would be greatly appreciated.

You need to use class function to be able to use it this way.
class func cycleTimer(toggleOn: Bool) {
However, I'm not sure about thread safety.

The function you have specified is not a class function. Add class keyword before func keyword.
The changed code:
class func cycleTimer
Note: In the previous versions of Swift you must use the following code (and also in C or other languages):
static func cycleTimer

Related

Function with Completion in Timer Selector

I am declaring a function as such:
#objc func fetchDatabase(completion: ((Bool) -> Void)? = nil)
I'm allowing the completion to be nil so I can either call it as fetchDatabase() or as
fetchDatabase(completion: { (result) in
// Stuff in here
})
However, I am also trying to use this function in a #selector for a Timer. I am creating this timer using the following line:
Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(fetchDatabase), userInfo: nil, repeats: true)
Without the completion, this runs fine. However, with the completion added, I get an EXC_BAD_ACCESS error whenever the timer is run. Some help with correctly constructing this selector would be greatly appreciated, if this is in fact the error.
The selector passed to the timer only allows one of two possible signatures
someFunction()
someFunction(someLabel someParameter: Timer)
You can't pass your fetchDatabase(completion:) function because it doesn't match either of the two legal selector signatures.
You need to pass a valid selector which in turn calls your fetchDatabase(completion:) function. For example:
#objc timerHandler() {
fetchDatabase(completion: { (result) in
// Stuff in here
})
}
use #selector(timerHandler) with your timer.
Default arguments get applied at the calling site, so you'll need to generate two separate methods (one of which calls the other):
func fetchDatabase() { fetchDatabase(callback:nil) }
func fetchDatabase(callback:()->()) {
...
}
Now your scheduledTimer call should work fine.

Swift: Value of type has no member 'peformSelector'

I'm trying to implement protocol/delegate using performSelector but I'm getting this error:
Value of type 'DoingSomething' has no member 'peformSelector'
Here is my implementation:
import UIKit
protocol DoingSomethingDelegate {
// delegate function
}
class DoingSomething {
func goDoSomething()
self.performSelector(onMainThread: #selector(self.processSomething()), with: nil, waitUntilDone: true)
}
func processSomething() {
print("I'm done")
}
}
But if I move the functions to the viewController I have no errors. Any of you knows why of the error or how can I fix this error?
I'll really appreciate your help.
Per #dan comment I made the changes:
class DoingSomething:NSObject {
func goDoSomething() {
self.performSelector(onMainThread: #selector(self.processSomething), with: nil, waitUntilDone: true)
}
func processSomething() {
print("I'm done")
}
}
Now is working!
As #vandian suggests in his comment, you should think about using GCD instead. The equivalent code would be:
DispatchQueue.main.async {
self.processSomething()
}
There are a couple of advantages to using async(). You can provide the code in-line without having to write a separate function, which makes it easier to read and maintain; The closure you execute has access to the enclosing scope, so you can use variables from your function inside that code, e.g.:
func localScopeFunc {
var x: Int = 6
DispatchQueue.main.async {
//This block of code has access to the local variables from localScopeFunc
print("x = \(x)")
}
}
With performSelector() and it's variants you can only invoke functions with zero, one, or 2 arguments, and those arguments must be NSObjects.
Forcing an object to be a subclass of NSObject also has some minor down-sides to it. That forces the compiler to use dynamic dispatching, which is slightly slower than the static dispatching that Swift uses.

Reusable Swift extension and selectors

Does exist any solution to make reusable protocol extension for more classes with selectors which would point to itself?
For example I am trying to make extension TimerHelper which adds appropriate functions to work with NSTimer. I found this:
https://forums.developer.apple.com/thread/26983
https://forums.developer.apple.com/message/49465#49465
But solution seems a bit twisty...
What I am trying to make in code, which doesn't work of course, is something like this:
protocol TimerHelper {
var timer:NSTimer { get set }
}
extension TimerHelper {
func startTimer() {
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: self.updateTimer(), userInfo: nil, repeats: true)
}
func updateTimer() {
print("Timer updated.")
}
}
class ViewController: UIViewController, TimerHelper {
var timer: NSTimer = NSTimer()
func start() {
startTimer()
}
}
Thanks
Never do:
... = NSTimer()
Instead create the variable as an optional. You want to invalidate and destroy the timer, and you never want a timer that hasn't been configured properly or invalidated.
Your extension is inappropriate because it deals with aspects not covered by the protocol itself. You should have 2 protocols, where the second protocol extends the first and is called something like TimerActivation. It defines the functions and the extension implements them.
This doesn't change what you need to do in the VC to use the timer, but it makes your type system clean, effective, reusable and extensible.
For the self referential part you need to look at #selector, I haven't tried it inside a protocol before, should be interesting...
It may be wiser to supply the selector, or an invocation, to the start function, because there is little point in a protocol extension implementing the selector when the protocol is so general. But, I suppose you may want to add other child protocols with extensions which provide other implementations so you can mixin functionality, interesting idea...

Assigning Functions from other Classes in Swift

Is it possible to access and run a specific method/function from another class that can change dynamically as the app is run?
I’ll try to simplify the problem as much as possible.
SelectionPage.swift
Choose which class needs to be selected and accessed using an UIPickerView - 10 possible selections (Class1, Class2, Class3,…, Class10).
Class1.swift, Class2.swift, … Class10.swift
Each of the 10 classes has a single method that has exactly the same name but is programmed differently:
func runOnUpdate() { }
GameSceneViewController.swift
When a selection is made on the SelectionPage, the app segues to a GameSceneViewController where the specific selected function is run every time the update function is run:
override func update(currentTime: CFTimeInterval)
{
// run runOnUpdate() function here from selected class
}
Inside the update function, I would like to execute the runOnUpdate( ) function depending on which class was selected on the SelectionPage. Is this possible? Ideally I'd like to be able to assign the specific class/method in the:
override func didMoveToView(view: SKView)
so that I can access in other functions as well.
I’ve looked into lazy instantiation, creating delegates for each of the classes, #objc(Class1), arrays of [AnyClass], typealias, global variables in structs, singletons etc. but I’m unable to figure out how to make this work.
It seems like a fairly common problem so any help would be greatly appreciated! Thank you in advance!
You were correct in trying delegates as this is a case where you should make a protocol and a delegate. The protocol requires the function. From there you set the delegate property to an instance of a class that conforms to that protocol and then you call delegate?.someFunction() to call the function on the given object.
class ViewController: UIViewController {
var delegate: Updatable?
override func viewDidLoad() {
super.viewDidLoad()
let foo = Foo()
delegate = foo
delegate?.runOnUpdate() // prints do something
}
}
protocol Updatable {
func runOnUpdate()
}
class Foo: NSObject, Updatable {
func runOnUpdate() {
println("do something")
}
}

Swift Multi-arg Selector is not getting called

Here is working code which runs fine in Objective-C,
[dataFetcher fetchDataWithRequest:authorizeRequest
delegate:self
didFinishSelector:#selector(didReceiveRequestToken:data:)
didFailSelector:#selector(didFailOAuth:error:)];
It is calling both methods in Objective-C.
But when I use Selector in Swift, it doesn't work.
dataFetcher?.fetchDataWithRequest(requestTokenRequest,
delegate: self,
didFinishSelector:Selector("didReceiveRequestToken:data:"),
didFailSelector: Selector("didFailOAuth:error:"))
Here the method which i'm calling,
func didReceiveRequestToken(ticket:OAServiceTicket,data:NSData){
}
I've already use solutions given on StackOverFlow but they didn't worked for me.
Thanks in Advance.
It`s good a bit change in your method:
func didReceiveRequestToken(ticket:OAServiceTicket,andData data:NSData){
}
The selector is: "didReceiveRequestToken:andData:"
Your call:
dataFetcher?.fetchDataWithRequest(requestTokenRequest,
delegate: self,
didFinishSelector:"didReceiveRequestToken:andData:",
didFailSelector:"didFailOAuth:andError:") // Make the same with this.
Be sure your code have this method.
Possibly, you are forgetting to use #objc in front of your method implementations:
#objc func didReceiveRequestToken(ticket:OAServiceTicket,data:NSData) {
....
This is required when the the target method is not defined inside of a class derived from NSObject (i.e., with pure-Swift classes).

Resources