bind(_:to:withKeyPath:options:), Swift Error, Xcode 14.3 Mac mini(M1)

Several years ago, I modified an [Apple Obj-c Time Zone] example (illustrated image below) to enrich my non-existent knowledge with Time Zones. The modified application illustrates the current [Time Zone Date and Time] for my current MDT location, and will illustrate another available [Time Zone Location] from a popup button.

So, I decided to see whether I could convert the Obj-c code to Swift code. The converted Swift code built properly, but the application will repeatedly crash when I engage the Swift [clockAndCalendar binding].

The Swift code application generates the following error message:

I understand the error message listed above to be: "EXC_BAD_ACCESS" error message (code=1, address=0x0) occurs when the application tries to access memory, which the application cannot access, or does not exist.

Examining the error shows the MDT’s as the first encountered location:

When I examine the additional [information] button, Xcode generates the following message, stating a [Foundation] incompatibility exists. Again, I wonder whether this issue can be resolved.

So, for the moment, I believe I cannot produce an equivalent Swift file just yet without more knowledge, where I unwittingly, and most likely applied the Swift [clockAndCalendar binding] code incorrectly … ?

I am curious about what I should do next, and how I might properly approach this error message ... ?

NSTimeZone (Obj-c) and TimeZone (Swift) produce different [Time Zone] results, as noted in the associated [Print Statements].

Your possible suggestions for me to explore would be very welcome … :]

Again, I must thank you for your time with this issue.

Best regards,

jim_k

// The modified Obj-c View:

//  Obj-c [setupCityClock] code:

- (void)setupCityClock:(NSView *)containerView timeZone:(NSTimeZone *)timeZone {

    NSDatePickerElementFlags flags = 0;
    flags |= NSDatePickerElementFlagHourMinute;
    flags |= NSDatePickerElementFlagHourMinuteSecond;
    flags |= NSDatePickerElementFlagTimeZone;
    flags |= NSDatePickerElementFlagYearMonth;
    flags |= NSDatePickerElementFlagYearMonthDay;
    flags |= NSDatePickerElementFlagEra;
    
    // Setup the city block and bind its value to a single NSDate property.
    NSDatePicker *theIdentifiedTimeZoneLocationCalendarAndClock = [[NSDatePicker alloc] initWithFrame:containerView.bounds];
    // Draw the [Focus Ring] around the [Date Picker]
    theIdentifiedTimeZoneLocationCalendarAndClock.focusRingType = NO;
    // Draw the [datePicker Background colour] which makes the [background colour darker]
    theIdentifiedTimeZoneLocationCalendarAndClock.drawsBackground = YES;
    // Set the [datePicker Background Colour] to [TEXT BACKGROUND COLOUR]
    theIdentifiedTimeZoneLocationCalendarAndClock.backgroundColor = NSColor.blackColor;
    // Set the [datePicker Text Colour] to [WHITE]
    theIdentifiedTimeZoneLocationCalendarAndClock.textColor = NSColor.controlTextColor;
    //  If the function is set to [YES] the [BORDER] is not [DRAWN] properly.
    //  Setting the function to [NO] will not draw the [BORDER]
    theIdentifiedTimeZoneLocationCalendarAndClock.bordered = NO;
    //  Set the [DATE PICKER STYLE]
    theIdentifiedTimeZoneLocationCalendarAndClock.datePickerStyle = NSDatePickerStyleClockAndCalendar;
    //  Set the [DATE PICKER ELEMENTS]
    theIdentifiedTimeZoneLocationCalendarAndClock.datePickerElements = flags;
    //  Set the [TIME ZONE]
    theIdentifiedTimeZoneLocationCalendarAndClock.timeZone = timeZone;
    
//  Check the results:

    NSLog(@"The [CURRENT TIME ZONE FOR (setupCityClock)] :: %@", timeZone);
    //  Prints: - [America/Edmonton (MDT) offset -21600 (Daylight)]
    //  Prints: - [Europe/London (GMT+1) offset 3600 (Daylight)]
    
    NSLog(@"The [CURRENT TIME ZONE FOR (setupCityClock) again] :: %@", theIdentifiedTimeZoneLocationCalendarAndClock.timeZone);
    //  Prints: - [America/Edmonton (MDT) offset -21600 (Daylight)]
    //  Prints: - [Europe/London (GMT+1) offset 3600 (Daylight)]
   
    //  Bind the [TIME ZONES] to the [CURRENT TIME]
    [theIdentifiedTimeZoneLocationCalendarAndClock bind:NSValueBinding toObject:self withKeyPath:@"currentTime" options:nil];
    //  Add the [CITY CLOCK] to the [CONTAINER VIEW]
    [containerView addSubview:theIdentifiedTimeZoneLocationCalendarAndClock];
    
}   //  End of [- (void)setupCityClock:]

// The modified Swift View [Without the [clockAndCalendar binding] engaged]: // NOTE: The clock’s static time differential is correct with each popup button selection.

//  Swift [setupCityClock] code:

func setupCityClock(containerView: NSView, timeZone: TimeZone) {
        
        var flags = NSDatePicker.ElementFlags()
        
        flags.insert(.hourMinute)
        flags.insert(.hourMinuteSecond)
        flags.insert(.timeZone)
        flags.insert(.yearMonth)
        flags.insert(.yearMonthDay)
        flags.insert(.era)
        
        // Setup the city clock and bind its value to a single NSDate property.
        let theIdentifiedTimeZoneLocationCalendarAndClock = NSDatePicker(frame: containerView.bounds)
        //  Draw the [Focus Ring] around the [Date Picker]
        theIdentifiedTimeZoneLocationCalendarAndClock.focusRingType = .none
        //  Draw the [datePicker Background colour] which makes the [background colour darker]
        theIdentifiedTimeZoneLocationCalendarAndClock.drawsBackground = true
        //  Set the [datePicker Background Colour] to [TEXT BACKGROUND COLOUR]
        theIdentifiedTimeZoneLocationCalendarAndClock.backgroundColor = NSColor.black
        //  Set the [datePicker Text Colour] to [WHITE]
        theIdentifiedTimeZoneLocationCalendarAndClock.textColor = NSColor.controlTextColor
        //  If the function is set to [YES] the [BORDER] is not [DRAWN] properly.
        //  Setting the function to [NO] will [NOT] draw the [BORDER]
        theIdentifiedTimeZoneLocationCalendarAndClock.isBordered = false
        //  Set the [DATE PICKER STYLE]
        theIdentifiedTimeZoneLocationCalendarAndClock.datePickerStyle = .clockAndCalendar
        //  Set the [DATE PICKER ELEMENTS]
        theIdentifiedTimeZoneLocationCalendarAndClock.datePickerElements = flags
        //  Set the [TIME ZONE]
        theIdentifiedTimeZoneLocationCalendarAndClock.timeZone = timeZone
        
        print("The [CURRENT TIME ZONE FOR (setupCityClock)] :: \(timeZone)")
        //  Prints: - [America/Edmonton (fixed (equal to current))]
        //  Prints: - [Europe/London (fixed)]

       //  Bind the [TIME ZONES] to the [CURRENT TIME] <=== (The error occurs here)
        theIdentifiedTimeZoneLocationCalendarAndClock.bind(.value, to: self, withKeyPath: "currentTime", options: nil)
        
        //  Add the [CITY CLOCK] to the [CONTAINER VIEW]
        containerView.addSubview(theIdentifiedTimeZoneLocationCalendarAndClock)
        
    }   //  End of [func setupCityClock(containerView: NSView, timeZone: TimeZone)]

Accepted Reply

After scouring the internet to see whether I could discover a solution with better key words, such as [Binding and NSView], I noticed a quote posted more than five years ago, stating the following:

Since KVC and KVO are built on the Objective-C runtime, and since Cocoa Bindings is built on top of KVC and KVO, any properties you want to use Cocoa Bindings with need to be exposed to Objective-C. At the bare minimum, that means adding @objc to the declaration.

So, my original [Date] property was set to: var currentTime: Date?

I changed the [Date] property to: @objc var currentTime: Date?

The application did not crash, but did not show the [Clock and the Calendar] updating.

Further reading stated: However, if the property can be changed at runtime, there's an additional hurdle you need to jump through; you need to make sure that the KVO notifications will fire whenever the property's setter is called. Apple's implementation of KVO will use Objective-C magic to automatically add the needed notifications to the setter, but since Swift property accesses aren't guaranteed to go through the Objective-C runtime, you need to add the dynamic keyword for this to work reliably.

I changed the [Date] property to: @objc dynamic var currentTime: Date?

The application did not crash, and the [Clock and the Calendar] updated properly.

Perfect, I now have that knowledge ... :]

Again, thank you for your time ...

Best regards,

jim_k

London:

Sydney:

Replies

After scouring the internet to see whether I could discover a solution with better key words, such as [Binding and NSView], I noticed a quote posted more than five years ago, stating the following:

Since KVC and KVO are built on the Objective-C runtime, and since Cocoa Bindings is built on top of KVC and KVO, any properties you want to use Cocoa Bindings with need to be exposed to Objective-C. At the bare minimum, that means adding @objc to the declaration.

So, my original [Date] property was set to: var currentTime: Date?

I changed the [Date] property to: @objc var currentTime: Date?

The application did not crash, but did not show the [Clock and the Calendar] updating.

Further reading stated: However, if the property can be changed at runtime, there's an additional hurdle you need to jump through; you need to make sure that the KVO notifications will fire whenever the property's setter is called. Apple's implementation of KVO will use Objective-C magic to automatically add the needed notifications to the setter, but since Swift property accesses aren't guaranteed to go through the Objective-C runtime, you need to add the dynamic keyword for this to work reliably.

I changed the [Date] property to: @objc dynamic var currentTime: Date?

The application did not crash, and the [Clock and the Calendar] updated properly.

Perfect, I now have that knowledge ... :]

Again, thank you for your time ...

Best regards,

jim_k

London:

Sydney: