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

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.

Related

SwiftUI calling helper functions from another swift class?

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.

How to use inout variables with closures defined by other sources?

I'm relatively new to Swift and was wondering how I could achieve this exact thing.
I have a Swift process, and I want to toggle a flag on completion, and I have the following code:
task.terminationHandler = { process in
isTaskComplete.toggle()
}
I have this exact code duplicated in various views and was trying to convert it to a function, with my first attempt of referencing the isTaskComplete flag by using inout.
However, because terminationHandler itself defines the parameters of the closure it takes, there is no way for me to attach a secondary inout parameter. I was wondering if there was any way for me to reference the flag inside the closure and have the value be referenced?
For what it's worth in using Swift 5 and Xcode 11.5.
Any help will be greatly appreciated! Thanks :)
You can use protocols and protocol extensions for that.
protocol NameYourProtocol {
var task: TypeOfTask { get } // { get set } If you need
var isTaskComplete: Bool { get }
}
extension NameYourProtocol {
func handleTermination() {
task.terminationHandler = { process in
isTaskComplete.toggle()
}
}
}
And this is what you will do in every class you need to call it:
class Worker: NameYourProtocol {
// This will be required by protocol.
var task = TypeOfTask()
var isTaskComplete = false
init() {
// Call `handleTermination` where you need to.
handleTermination()
}
}

Class hierarchy - class should only called by another class

I try to implement a Security class and a Secret class. In my whole project the Secret class should only called by Security.getSecretInstance().doSomeSecretAction()
So Secret.doSomeSecretAction() should throw an compile error.
I need the Security.getSecretInstance() for an authentication process.
I'm searching for a good pattern or something else, but I think my searching keywords are too bad or my requirement is stupid/or not possible.
At the moment I call Security.getSecretInstance() it returns a singleton instance of Secret, but I could call Secret.doSomeSecretAction() too. There is no difference.
Do you have some pattern, keywords or snippets for me?
Edit
My definition of awesome would be that I have one method like this:
Security.isAuthorized { secret in
secret.doSomeSecretAction
}, failure {
print("permission denied")
}
And I can get secret only with this .isAuthorized-Method
What I would recommend doing is declare Secret nested inside Security, make Secret private and create non-private methods inside Security that can access Secret. Something like this:
class Security {
class func doSomeSecretAction() {
Secret.doSomeSecretAction()
}
private class Secret {
class func doSomeSecretAction(){
print("Private method called")
}
}
}
Security.doSomeSecretAction()
Here, Security.doSomeSecretAction() can be called from outside the Security class, but Secret.doSomeSecretAction() can only be called inside the Security class.
Update based on comments:
A feasible solution would be declaring the initializer of Security private, so it can only be called from inside the Security class and declaring a computed variable (for now I called it shared) which is the only access point to the initializer. This computed variable either returns nil or a new instance of the Secret class based on Security.isAuthorized. This way, every time a function of Secret is called, the authorisation status is checked and the function can only be called if the status is authorised, otherwise the shared variable returns nil and hence the method is not called.
class Security {
static var isAuthorized = false //change this when the authorisation status changes
class Secret {
static var shared: Secret? {
if Security.isAuthorized {
return Secret()
} else {
return nil
}
}
private init(){} //a new instance of Secret can only be created using the `shared` computed variable, the initializer cannot be called directly from outside the Secret class
func doSomeSecretAction(){
print("Private method called")
}
}
}
Security.Secret.shared //nil
//Security.Secret.init() //if you uncomment this line, you'll get an error saying all initializers are inaccessible
Security.Secret.shared?.doSomeSecretAction() //nil
Security.isAuthorized = true
Security.Secret.shared?.doSomeSecretAction() //function is called
Security.isAuthorized = false
Security.Secret.shared?.doSomeSecretAction() //nil
I was working on this answer while Dávid was editing his; I didn't realize he'd posted an update awhile ago. There's a lot of overlap in our answers, so this is just another style of the same approach.
First, I want to be clear that what you're describing can only implement encapsulation, not "security." I mean that you can build a system that makes it easy for developers to use it correctly and difficult to use it incorrectly. That's pretty straightforward. But you won't be able to stop a developer from extracting the secret and running any code they want. It's their machine and you're giving them the code. They can always run it. They have a debugger; you're not going to hide anything.
But, preventing accidental misuse is a fine goal, and pretty straightforward. The first thing is that you should work with instance methods, not class methods. Class methods makes all of this harder than it needs to be. A solution to your problem will look something like this, relying on fileprivate for most of the access control.
class Security {
enum Error: Swift.Error {
case unauthorized
}
// This feels like it should be nested in Security, but doesn't have to be
class Secret {
// No one outside this file can instantiate one of these. It's likely
// that you'll be passing some parameters here of course.
fileprivate init() {}
// I'm assuming you want these to be single use, so people can't store
// a reference to them an reuse them. This is one simple way.
fileprivate var isAuthorized = true
private func validate() {
// I'm treating this kind of reuse as a programming error and
// crashing. You could throw if you wanted, but it feels like it
// should never happen given your design.
guard isAuthorized else {
fatalError("Secrets can only be used once")
}
}
func doSomeSecretAction() {
// Every "protected" method (which may be all of them) needs to
// call validate() before running.
validate()
print("SECRET!")
}
}
// Public so we can test; obviously this would at least private(set)
var isAuthorized = false
func withAuthorization(execute: (Secret) -> Void) throws {
guard isAuthorized else { throw Error.unauthorized }
// We create a new Secret for every access and invalidate it after.
// That prevents them from being stored and reused.
let secret = Secret()
execute(secret)
secret.isAuthorized = false
}
}
// -- Some other file
let security = Security()
security.isAuthorized = true // For testing
var stealingTheSecret: Security.Secret?
do {
try security.withAuthorization {
$0.doSomeSecretAction() // This is good
stealingTheSecret = $0 // Try to steal it for later use
}
} catch Security.Error.unauthorized {
print("Unauthorized")
}
stealingTheSecret?.doSomeSecretAction() // Let's use it: Crash!
In principle you could get rid of the validate() boilerplate by allocating the memory for Secret directly with UnsafeMutablePointer and destroying it at the end, but this is probably more trouble than it's worth to avoid one extra line of code.
(Note that allocating the memory yourself still wouldn't protect you against the caller saving the object; they can always make a copy of the memory and re-instantiate it with .load; any unsafe thing you can do, so can the caller. This also allows them to circumvent validate() by directly modifying the boolean or copying the object before you invalidate it. There is no technique that will prevent unsafe memory access; this is why you cannot protect secrets inside code.)
After research I find a good and simple solution for me:
class SecurityLayer {
private static var authorized: Bool = false
static func makeAuthorizeCheck() -> API2? {
if authorized {
return API2()
}
return nil
}
}
Second class (not subclass)
class Secret {
func test() {
print("test")
}
fileprivate init() {
}
}
Examples
SecurityLayer.makeAuthorizeCheck()?.test() //working
Secret() //forbidden
Secret.test() //compiler find this method, but there are no permissions to use this one
When the constructor inside Secret is private this wouldn't work anymore. For me the benefit of fileprivate is obvious now.
!The classes have to be in one file!

How to convert String to Struct (in Swift)

I have a struct like,
struct LoginConstants {
struct Selectors {
let testa = "test1234"
}
}
and a class like,
class Login: XCTestCase {
override class func setUp () {
// below constant will have a value like "LoginConstants"
let localConstants = "\(String(describing: self))Constants"
}
}
... so here I have a struct-name as a string format in localConstants.
My Question is how I can access the LoginConstants properties from the localConstants string?
NOTE:
I know I can access the LoginConstants() directly.
But I am planning to create a parent class where I can access this ***Constants struct dynamically.
Thanks for the help!
Objective-C has the ability to do this, but Swift does not. If you give a class an Objective-C name via the #objc attribute, you can use the Objective-C runtime functions to access it by name. However, this is not possible with a struct.
It's probably not the best way to go anyway. A better solution is to rethink what you are trying to do, and access the struct type directly rather than by name.

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() {
}
}