Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-7576] NSNumber to Float bridging results in crash with Swift 4.1 on iOS9+CABasicAnimation #3710

Open
swift-ci opened this issue May 1, 2018 · 2 comments

Comments

@swift-ci
Copy link
Contributor

swift-ci commented May 1, 2018

Previous ID SR-7576
Radar None
Original Reporter stonehouse (JIRA User)
Type Bug
Environment

Developer machine:
Xcode 9.3 9E145
Swift 4.1 'swiftlang-902.0.48'
Test device:
iPod Touch
iOS 9.3.5 (13G36)

Additional Detail from JIRA
Votes 0
Component/s Foundation
Labels Bug, 4.1Regression
Assignee None
Priority Medium

md5: 3fb56679807fff4408f2adb44e525772

Issue Description:

Casting Float to NSNumber results in nil in cases where it cannot be cleanly represented.

This seems to be related to SR-5179, and it seems from looking at SR-5228 that this may be an intentional change to avoid lossy conversion. However, I wanted to point out that this behaviour leads to crashes on iOS 9 when using CABasicAnimation and animating CGFloat properties.

I recently discovered that our app started crashing on iOS 9 after the upgrade to Xcode 9.3/Swift 4.1. I've determined the cause is this issue happening somewhere in CABasicAnimation. If I don't specify `fromValue` then it works fine. This crash does not happen in iOS 10 or later.

The problem with this crash is that it results inside CoreAnimation code, so the developer needs to either disable the animation on iOS 9 or sanitise Float values before passing them in.

If I should file a radar let me know, but it seems like the problem is with Swift, because the issue doesn't exist in iOS 10 or later.

The following exception is thrown on an iOS 9 device when attempting to run the animation

Fatal error: Unable to bridge NSNumber to CGFloat: file /BuildRoot/Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-902.0.48/src/swift/stdlib/public/SDK/Foundation/NSNumber.swift, line 606

Here is a simplified example of the kind of animation that might crash on iOS 9

import UIKit

class SampleLayer: CALayer {
    var brightness: CGFloat = 0
    
    @objc dynamic var locations: [CGFloat] = [0.0, 1.0] {
    didSet {
        setNeedsDisplay()
    }
    }
    
    func setBrightnessAnimated(_ brightness: CGFloat, duration: CFTimeInterval, timingFunction: CAMediaTimingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)) {
        let oldBrightness = self.brightness
        let newBrightness = brightness
        
        // On iOS 9 with Swift 4.1 this is crashing due to a bug where CGFloat cannot be cast to NSNumber in some conditions
        if duration > 0 {
            let oldLocations = presentation()?.locations ?? [0, oldBrightness]
            let animation = CABasicAnimation(keyPath: "locations")
            animation.duration = duration
            animation.fromValue = oldLocations
            animation.timingFunction = timingFunction
            removeAnimation(forKey: "brightness")
            add(animation, forKey: "brightness")
        }
        
        self.brightness = newBrightness
    }
}

let testLayer = SampleLayer()
testLayer.setBrightnessAnimated(1, duration: 0.1)
@belkadan
Copy link

belkadan commented May 1, 2018

@phausler?

@swift-ci
Copy link
Contributor Author

swift-ci commented Jun 1, 2018

Comment by Alexander Stonehouse (JIRA)

Just wanted to update, I couldn't reproduce this on iOS 10, but now that I've started to roll out the changes, I've seen numerous crash logs from users on iOS 10.3.3.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
@shahmishal shahmishal transferred this issue from apple/swift May 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants