SwiftUI calling helper functions from another swift class? - swift

I have created my app using swiftui. Then I found that sometimes I may need to do some tasks quite frequently. Instead of placing it in the same swiftui files, I think that it should be placed inside another class. However, I wonder how can we call the function of another class inside swiftui? is that I must have new an object to call it?

As I understand your question:
class MyHelper {
static func helpMe(needHelp: Bool) -> String {
if(needHelp) {
return "Help in on the way!"
} else {
return "You are ok!"
}
}
}
Usage:
let result = MyHelper.helpMe(needHelp: true)
You can use static or class functions inside the helper class, and access to them by '.' syntax. Difference between static and class functions, that you can override class function in the subclass (which is not really needed with helper classes), static not.

Related

Hiding inner class in swift

I'm trying to hide a inner class so the caller is not aware of it. If the caller want, they can get an instance of the inner class by using a public method. But the caller should not be able to directly get the inner class.
Example to show what I want:
class A {
static func getSettings() -> Settings {
return Settings()
}
class Settings {
func turnOnSomeThing() {
}
}
}
class test {
func testFunc() {
A.getSettings().turnOnSomeThing() // correct way of calling
A.Settings().turnOnSomeThing() // should not be possible
}
}
Is this possbile in Swift?
Why do both calls work in the test caller?
Both currently work because:
The first case, A.getSettings()... is a classic getter that returns an object. I'm just puzzled with the fact that a new Settings is constructed each time, but this is perfectly legit.
The second case, A.Settings().... invokes the constructor of Settings to create an anonymous object, and invokes some methods on it. It's ok, because the inner class is public, but it's weird.
Can you make the inner class private?
You could make an inner class private to avoid it being accessed from the outside world:
This would work perfectly well for an private helper class totally invisible to the outside world.
For Settings this is not possible, because getSettings() returns objects of this class to the outside world, and this makes only sense if the outside world knows the class to deal with it.
Exemple:
class A {
static func getSettings() -> Settings { // ERROR if Settings would be private
let helper = Helper() // purely internal use: Helper can be private :-)
helper.demo()
return Settings()
}
class Settings { // making private is not possible (see above)
func turnOnSomeThing() {
print ("On")
}
}
private class Helper { // Cannot be used outside
func demo() {
print ("Demo")
}
}
}
But how to do with Settings?
If you want to return Settings objects to the wild outside world you need to keep that class public. However, if you want to avoid that the outside world misues the inner class and avoid objects to be created from the outside wolrd, you can use access control on the constructor:
class A {
static func getSettings() -> Settings {
...
}
class Settings {
fileprivate init() { /// <=== ACCESS CONTROL internal or fileprivate
}
func turnOnSomeThing() {
...
}
}
}
This prevents the calls of the form A.Settings()..., but only according to swift access control: with internal you can still call the constructor from another file of the same module; with fileprivate the constructor can only be called from within the source file in which you've defined your external class.
This technique of making the constructor inaccessible while keeping the class usable is frequently used for classes which instances shall only be created via a factory.

In Swift, how to determine what property called a function? is it possible?

I have a struct like,
struct LoginPage {
static let usernameField = Element("#username")
}
and I have a class like,
class LoginView {
func enterCredentails () {
LoginPage.usernameField.waitForExist()
}
}
and the Element api looks like
class Element {
init(...) {
...
}
func waitForExist () {
// print("caller property name")
}
}
...here inside waitForExist() I want to get that property name(usernameField) who triggered this method. so that I can print the error and success message dynamically inside waitForExist() based on the property name.
is this possible? is there any workaround for this?
NOTE: I have tried using Mirror to get all the properties(so that I can store and retrieve the key name based on Element), but it is not returning the static properties (Referred). So I am looking for the alternative solution.
Thanks in advance for helping me out!
I'd recommend the simple approach:
func waitForExist(propertyName: String [or possibly make it an enum]) {
// do what needs to be done
}
I'm assuming your properties call this in their didSet or something; just have each one pass the appropriate value to the waitForExist function.
As for the literal answer to your question, you could probably examine the stack using functions like backtrace(), but ehhhhhh... trust me, you don't really want to do that.

Extending a class with instance method

I'm trying to extend the functionality of a existing type in Swift. I want to use dot syntax to call the methods on the type.
I want to say:
existingType.example.someMethod()
existingType.example.anotherMethod()
I'm currently using an extension like so:
extension ExistingType {
func someMethod() {
}
func anotherMethod() {
}
}
existingType.someMethod()
existingType.anotherMethod()
Doing this will expose too many functions. So, I want to write these methods in a class, and just extend the ExistingType to use an instance of the class. I'm not sure the right way to go about this.
if I were actually implementing the existing type, I would do the following:
struct ExistingType {
var example = Example()
}
struct Example {
func someMethod() {
}
func anotherMethod() {
}
}
Allowing me to call the methods by:
let existingType = ExistingType()
existingType.example.someMethod()
The issue is I'm not implementing the type, because it already exists. I just need to extend it.
It looks like you are trying to add another property example the existing class ExistingType and call methods of that property. You cannot add properties in extensions, though. The only way to add another property to the existing class is to subclass it.
You can create a new struct.
struct NewType {
let existingType: ExistingType
func someMethod() {
}
func anotherMethod() {
}
}

Can a Swift class be extended multiple times with the same methods?

I am designing a framework that uses protocols and extensions to allow for third-parties to add support for my framework to their existing classes.
I'd also like to include some built-in extensions for known classes like UIView, but I don't want to prevent users from defining their own additional support for the same classes.
My question is is there any way that I can extend the same class twice, and override the same (protocol) method in that class both times, while still having some way to call the other if the first one fails.
Elaboration: I really have three goals here I want to achieve:
I want to allow users of my framework to provide their own extensions for their own (or any) UIView subclasses.
I also need some way to allow general behavior that can apply to all UIViews as a fallback option (i.e. if the specific class extension can't handle it, fall back on the generic UIView extension).
I'd also like to separate out my own implementation, by providing some built-in generic view handling, but in such a way that it doesn't prevent third parties from also defining their own additional generic handling. (If I can't do this, it's not a big deal, the first two parts are the most important.)
I have part 1 working already. The problem is how to get this fallback behavior implemented. If I do it all with extensions, the subclass will override the superclass's implementation of the protocol method. It could call super.method, but I'd like to avoid putting that responsibility on the subclass (in case the author forgets to call super).
I'd like to do this all from the framework code: first, call the object's protocol method. If it returns false, I'd like to somehow call the generic UIView handler.
Now that I'm typing it all out, I'm wondering if I can just use a different method for the generic fallback and be done with it. I just figured it would be elegant if I could do it all with one method.
No! It can't be extended multiple times.
extension Int {
var add: Int {return self + 100} // Line A
}
extension Int {
var add: Int {return self + 105} //Line B
}
Doing so would create a compile time error ( on Line B) indicating: Invalid redeclaration of 'add'
Swift is a static typing language and helps you find these sorts of errors before runtime
In Objective-C you can write this and still not get an error, however the result would be undefined, because you wouldn't know which method gets loaded first during runtime.
Overriding a single protocol method twice in 2 separate extensions wouldn't work, because the protocol method names would collide. Once compiled, they're all just methods on the same class. With that in mind, perhaps put all the protocol methods in their own extension & call them from within the other ones?
The following could be one general option. Could get messy if you decide to keep adding additional extension functionality.
class baseClass {
//stuff
}
extension baseClass: myProtocol {
override func myProtocolMethod(args) -> returnType {
//Repeat this in a separate extension & your method names collide
var status: Bool
//protocol method code sets status as appropriate...
return status = true ? optOne(status) : optTwo(status)
}
func optOne(status:Bool) -> returnType{
//do the 'true' thing
return returnType
}
func optTwo(status:Bool) -> returnType{
//do the 'false' thing
return returnType
}
}
extension baseClass {
var oneExtension = myProtocolMethod(someArg)
}
extension baseClass {
var twoExtension = myProtocolMethod(someArg)
}
I realize this Question is over a year old and the original poster has probably moved on to other things, but I'd like to share an idea anyways and perhaps get some feedback.
You say that you want a method that can be overwritten multiple times. The short answer, like many in this thread have given is no, but the long answer is yes.
We can solve the issue with a bit of generic magic.
class MyView: UIView {
var customizer: MyProtocol<MyView> = Defaults()
func willCallCustomizer() {
customizer.coolMethod(self)
}
}
// Use this class as if it were a protocol
class MyProtocol<T: UIView>: NSObject {
func coolMethod(_ view: T) {}
}
// Class inherits from the "protocol"
class Defaults: MyProtocol<MyView> {
override func coolMethod(_ view: MyView) {
// Some default behavior
}
}
/// on the clients end...
class CustomerCustomizer: MyProtocol<MyView> {
override func coolMethod(_ view: MyView) {
// customized behavior
}
}
So if the client wants to use their own customizer they can just set it, otherwise it will just use the default one.
myViewInstance.customizer = CustomerCustomizer()
The benefit of this approach is that the client can change the customizer object as many times as they want. Because MyProtocol is generic, it may be used for other UIView's as well; thus fulfilling the role of a protocol.

How do I declare a class level function in Swift?

I can't seem to find it in the docs, and I'm wondering if it exists in native Swift. For example, I can call a class level function on an NSTimer like so:
NSTimer.scheduledTimerWithTimeInterval(0.2, target: self, selector: "someSelector:", userInfo: "someData", repeats: true)
But I can't seem to find a way to do it with my custom objects so that I could call it like:
MyCustomObject.someClassLevelFunction("someArg")
Now, I know we can mix Objective-C w/ Swift and it's possible that the NSTimer class method is a remnant from that interoperability.
Question
Do class level functions exist in Swift?
If yes, how do I define a class level function in Swift?
Yes, you can create class functions like this:
class func someTypeMethod() {
//body
}
Although in Swift, they are called Type methods.
You can define Type methods inside your class with:
class Foo {
class func Bar() -> String {
return "Bar"
}
}
Then access them from the class Name, i.e:
Foo.Bar()
In Swift 2.0 you can use the static keyword which will prevent subclasses from overriding the method. class will allow subclasses to override.
UPDATED: Thanks to #Logan
With Xcode 6 beta 5 you should use static keyword for structs and class keyword for classes:
class Foo {
class func Bar() -> String {
return "Bar"
}
}
struct Foo2 {
static func Bar2() -> String {
return "Bar2"
}
}
From the official Swift 2.1 Doc:
You indicate type methods by writing the static keyword before the method’s func keyword. Classes may also use the class keyword to allow subclasses to override the superclass’s implementation of that method.
In a struct, you must use static to define a Type method. For classes, you can use either static or class keyword, depending on if you want to allow your method to be overridden by a subclass or not.
you need to define the method in your class
class MyClass
{
class func myString() -> String
{
return "Welcome"
}
}
Now you can access it by using Class Name eg:
MyClass.myString()
this will result as "Welcome".