Search code examples
iosswiftswiftuistructtimer

How to solve error where renaming struct causes errors for timer app in swift?


I am trying to create a timer that counts down so I can implement it to a app I am creating, here is a demo project: https://www.dropbox.com/scl/fo/h6uggyqzpwhxji76dv4ck/h?rlkey=5an6cwpshyft1f9q0y8p8gvk0&dl=0

The error I am facing is that when I change the struct name to something other then ContentView() I get this error:

Error when I rename struct

Error when I rename struct

But if the struct is ContentView() I get no error:

No error when struct name ContentView

No error when struct name ContentView

What can I do so I can name the struct something other then ContentView() and not get any errors (Like if I want to name the struct Timer() what should I do)?

Thanks in advance,

I tried to use a different timer method but could not find/understand any as I am new to swift.


Solution

  • What you experience is a "symbol look up" issue.

    The symbol "Timer" is already defined in module Foundation.

    Now, in fact one can define a language artefact in a module with a symbol which is already used in another module, without conflicts.

    There's only one catch: in oder to find the definition of a certain symbol, the compiler needs to "look it up". This can sometimes be ambiguous, in which case you get a compiler error. In your case, the statement

    let timer = Timer.publish(every: 1, on: .main, in: .common) .autoconnect()
    

    within a struct "Timer" lets the compiler find the symbol "Timer" from the struct, but not the symbol "Timer" from module "Foundation". So, the compiler gets "confused" and emits an error.

    Now, it's entirely possible to use the name "Timer" in your module – you just need to give the compiler a hint where to start the search. So, this can be achieved by giving the compiler (fully) qualified name for the symbol "Timer" in module "Foundation", i.e., you need to prefix the symbol with the module name:

    let timer = Foundation.Timer.publish(every: 1, on: .main, in: .common) .autoconnect()
    

    You can extend this concept to local symbols as well, and create a "name space" for your symbols. For the sake of demonstration, below a brief example:

    import Foundation
    
    enum TimerFeature {}
    
    extension TimerFeature {
    
        struct Timer {
            let every: TimeInterval
    
            let timer = Foundation.Timer  // needs qualified name!
            .publish(
                every: every, 
                on: .main, 
                in: .common
             )
            .autoconnect()
        }
    
    }
    

    Then, you can use your Timer with a fully qualified name to disambiguate the symbol look up for symbol "Timer":

    import Foundation
    
    // your Timer:
    let myTimer = TimerFeature.Timer(every: 1)  
    
    // Foundation Timer:
    let foundationTimer = Timer.publish(
        every: 1, 
        on: .main, 
        in: .common
    ).autoconnect()