skip to Main Content

I am trying to use the NSCalendar initializer but i’m having trouble understanding the documentation. what I have so far is

    struct SwiftUIView: View {
    var body: some View {
        
        
        let Date = NSCalendar.init(calendarIdentifier: .coptic)
        
        Text("(Date)")
        
        
        
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        SwiftUIView()
    }
}

its giving me an error saying
"Value of optional type ‘NSCalendar?’ must be unwrapped to a value of type ‘NSCalendar’"

if someone could help me figure this out, that would be great. Thank you

2

Answers


  1. The interface you want for Swift is Calendar rather than NSCalendar:

    let calendar = Calendar(calendarIdentifier: .coptic)
    

    The NSCalendar interface is from ObjC and is documented to return nil if the name of the calendar is unknown (you can pass arbitrary strings in ObjC for this parameter).

    The Swift Calendar interface cannot fail because it will not allow you to create an unknown identifier.

    There are many types that begin "NS" that are bridged from Objective-C. It is very common for there to be a Swift version that drops the "NS" prefix. When you see this, you should generally use the Swift version. It will generally behave in a more Swift-like way.

    If your goal is to display the current date on the Coptic calendar, however, you will need more than this. A calendar represents the whole calendar, not a particular date. You will need a DateFormatter in order to create a localized string.

    For example:

    let dateFormatter = DateFormatter()
    dateFormatter.dateStyle = .medium
    dateFormatter.calendar = Calendar(identifier: .coptic)
    dateFormatter.eraSymbols = ["BC", "AM"] // See below
    print(dateFormatter.string(from: Date()))
    
    // Baramouda 18, 1737 AM
    

    (I believe there is a bug in Calendar such that the Coptic calendar has era symbols "ERA0" and "ERA1". I believe the correct symbols for this calendar are "BC" and "AM". You can force this by assigning them directly to the date formatter. If I’m correct that this is a bug and it impacts you, I recommend opening an Apple Feedback. See also the DateFormatter documentation for how to customize this string.)

    To xTwisteDx’s point, to put this in SwiftUI you want something along these lines:

    struct ContentView: View {
    
        let dateFormatter: DateFormatter = {
            let dateFormatter = DateFormatter()
            dateFormatter.dateStyle = .medium
            dateFormatter.eraSymbols = ["BC", "AM"] // Workaround for Foundation bug
            dateFormatter.calendar = Calendar(identifier: .coptic)
            return dateFormatter
        }()
    
        func today() -> String {
            dateFormatter.string(from: Date())
        }
    
        var body: some View {
            Text(today())
                .padding()
        }
    }
    
    Login or Signup to reply.
  2. Ok so this is an issue with Optionals. Anytime you see ? or ! then you can assume that it is an optional. Essentially the reason that it is a Type?, notice the ? is because it’s possible that it has returned a nil value. For example the following snippets are possible in Swift

    let forceUnwrappedString: String!
    let optionalString: String?
    let safeString: String = "Hello World!"
    
    print(forceUnwrappedString) //This WILL crash, the variable is nil.
    print(optionalString) //This MAY crash, if the value is nil.
    print(safeString) //This WON'T crash.
    

    The way that you handle these is to check using if let or guard statements. Alternatively you can also force unwrap after checking for nil.

    If Let

    In this example, if optionalString is nil, the print statement WILL NOT happen. However if optionalString contains a value, it will. It’s essentially a way of telling the compiler to check for nil values and only run code if it’s safe.

    if let safeString = optionalString {
        print(safeString)
    }
    

    Guard

    In this example, it works the same as an If Let with a notable difference being that the safeString is accessible at a bigger scope than the If Let also it returns if the value is not "unwrapped" so any code below it will not be called if it’s not safely unwrapped.

    guard let safeString = optionalString { else return }
    print(safeString)
    

    Force Unwrapping

    Force unwrapping is something you should avoid however there are instances when it’s acceptable. This is an example of force unwrapping. Notice that I used the ! which basically says "I know this value is not nil, use it." That is the only time you should ever use it, when you can guarantee there isn’t a nil value.

    let someString: String? 
    
    someString = "Hello World!"
    
    print(someString!)
    

    Your Problem

    In the context of your issue, NSCalendar.init(calendarIdentifier: .coptic) returns an optional type or, someType? meaning it has the possibility to be nil The solution is below.

    let Date = NSCalendar.init(calendarIdentifier: .coptic)
            
    if let safeDate = Date {
            Text("(safeDate)")
    } else {
        //The date value was nil, do something else
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search