Need to cast array unexpectedly when using `addConstraints`

(wdb) #1

IDE: Fire
Version: Version 10.0.0.2398 (develop) built on bajor, 20190424-095707. Commit b865645.
Target (If relevant): _iOS
Description:
I am getting an error when I try to manage layout constraints while working with UITableViewCell. I keeping track of all the applied layout constraints (as seen in Eureka!) by defining the following: open var dynamicConstraints = [NSLayoutConstraint]().

Next I am adding a bunch of NSLayoutConstraint-instances like: dynamicConstraints += NSLayoutConstraint.constraints(visualFormat: "V:|-11-[textField]-11-|", options: .alignAllLastBaseline, metrics: nil, views: views)

If I now then try to add the constraints to a view using: contentView.addConstraints(dynamicConstraints) or remove them via contentView.removeConstraints(dynamicConstraints) I am getting the following compiler error:

E:                   Parameter 1 is "Swift.Array<NSLayoutConstraint!>", should be "NSArray<Dynamic<NSLayoutConstraint!>>!", in call to func UIView!.removeConstraints(_ constraints: NSArray<Dynamic<NSLayoutConstraint!>>!) [/Users/x/Development/Projects/x/x/version-3/config-app/x/Views/TextFieldCell.swift (71)]
E:                   Parameter 1 is "Swift.Array<NSLayoutConstraint!>", should be "NSArray<Dynamic<NSLayoutConstraint!>>!", in call to func UIView!.addConstraints(_ constraints: NSArray<Dynamic<NSLayoutConstraint!>>!) [/Users/x/Development/Projects/x/x/version-3/config-app/x/Views/TextFieldCell.swift (98)]

Expected Behavior:
I would expect I can directly apply the array without needing to cast it

Actual Behavior:
I need to cast the code to the following to make it compile contentView.removeConstraints(dynamicConstraints as! NSArray<Dynamic<NSLayoutConstraint!>>)

(wdb) #2

Hmm, if I try the following code:

        if let convertedConstraints = dynamicConstraints as? NSArray {
            Loggly.log("TextFieldCell.customConstraints(): Remove existing constraints")
            contentView.removeConstraints(convertedConstraints)            
        }

I am getting the following runtime error:

2019-04-24 15:15:59.540209+0100 XConfigiOS[32105:1747688] LOG: TextFieldCell.customConstraints(): Remove existing constraints
~> Ignored exception of type NSException on thread AAE8
~> Message: Null Reference Exception for expression: list()
2019-04-24 15:15:59.764388+0100 XConfigiOS[32105:1747688] *** Terminating app due to uncaught exception 'NullReferenceException', reason: 'Null Reference Exception for expression: list()'
*** First throw call stack:
(
        0   CoreFoundation                      0x00000001094136fb __exceptionPreprocess + 331
        1   libobjc.A.dylib                     0x0000000108341ac5 objc_exception_throw + 48
        2   CoreFoundation                      0x0000000109413555 +[NSException raise:format:] + 197
        3   XConfigiOS                     0x00000001080e213b -[__Swift_Array platformList] + 203
        4   XConfigiOS                     0x00000001080e1bdb -[__Swift_Array makeUnique] + 27
        5   XConfigiOS                     0x00000001080e25fa -[__Swift_Array append:] + 26
        6   XConfigiOS                     0x00000001080e1f97 +[__Swift_Array op_Addition:Array_lT_g_u_uISequence_lT_g:] + 263
        7   XConfigiOS                     0x0000000108043bb7 -[__XConfigiOS_TextFieldCell customConstraints] + 2551
        8   XConfigiOS                     0x0000000108043193 -[__XConfigiOS_TextFieldCell updateConstraints] + 67
        9   UIKitCore                           0x00000001157836c1 -[UIView(AdditionalLayoutSupport) _sendUpdateConstraintsIfNecessaryForSecondPass:] + 161
        10  UIKitCore                           0x0000000115783c88 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededCollectingViews:forSecondPass:] + 1236
        11  UIKitCore                           0x0000000115784411 __100-[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededWithViewForVariableChangeNotifications:]_block_invoke + 85
        12  UIKitCore                           0x0000000115783fa0 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededWithViewForVariableChangeNotifications:] + 155
        13  XConfigiOS                     0x0000000108042e23 -[__XConfigiOS_TextFieldCell layoutSubviews] + 163
        14  UIKitCore                           0x000000011584a9c1 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1417
        15  QuartzCore                          0x000000010ad5feae -[CALayer layoutSublayers] + 173
        16  QuartzCore                          0x000000010ad64b88 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 396
        17  UIKitCore                           0x0000000115835985 -[UIView(Hierarchy) layoutBelowIfNeeded] + 646
        18  UIKitCore                           0x000000011583ca19 +[UIView(Animation) performWithoutAnimation:] + 90
        19  UIKitCore                           0x00000001155b585b -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 1323
        20  UIKitCore                           0x00000001155b5b65 -[UITableView _createPreparedCellForGlobalRow:willDisplay:] + 73
        21  UIKitCore                           0x000000011557dd20 -[UITableView _updateVisibleCellsNow:isRecursive:] + 2870
        22  UIKitCore                           0x000000011559de37 -[UITableView layoutSubviews] + 165
        23  UIKitCore                           0x000000011584a9c1 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1417
        24  QuartzCore                          0x000000010ad5feae -[CALayer layoutSublayers] + 173
        25  QuartzCore                          0x000000010ad64b88 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 396
        26  QuartzCore                          0x000000010ad70ee4 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 72
        27  QuartzCore                          0x000000010ace03aa _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 328
        28  QuartzCore                          0x000000010ad17584 _ZN2CA11Transaction6commitEv + 608
        29  UIKitCore                           0x00000001153a43a4 _afterCACommitHandler + 245
        30  CoreFoundation                      0x000000010937a0f7 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
        31  CoreFoundation                      0x00000001093745be __CFRunLoopDoObservers + 430
        32  CoreFoundation                      0x0000000109374c31 __CFRunLoopRun + 1505
        33  CoreFoundation                      0x0000000109374302 CFRunLoopRunSpecific + 626
        34  GraphicsServices                    0x000000010dd8b2fe GSEventRunModal + 65
        35  UIKitCore                           0x000000011537cba2 UIApplicationMain + 140
        36  MatrixConfigiOS                     0x0000000108031948 +[AppDelegate Main::] + 56
        37  MatrixConfigiOS                     0x0000000108050d7c main + 44
        38  libdyld.dylib                       0x000000010b06d541 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(wdb) #3

I have the project privately shared with @ck and @mh (via private message). The project exists all the issues reported today :slight_smile:

Looks like it doesn’t like me reinitiating the array using dynamicConstraints = [] and then using this variable to append items using +=.

(RemObjects) #4

Thanks, logged as bugs://82460

(marc hoffman) #5

Can you do small-fish test cases for these? a huge cross-platform project with dozens of files really is hard to debug. (also, the project you sent compiles clean for me).

(marc hoffman) #6

this testcase repros the couple error for me:

	func test()
	{
		let views = [String:id]()
		var dynamicConstraints = [NSLayoutConstraint]()
		dynamicConstraints += NSLayoutConstraint.constraints(visualFormat: "V:|-11-[textField]-11-|", options: .alignAllLastBaseline, metrics: nil, views: views)
		let contentView = UIView()
		contentView.addConstraints(dynamicConstraints) // E486 Parameter 1 is "Swift.Array<NSLayoutConstraint!>", should be "NSArray<Dynamic<NSLayoutConstraint!>>!", in call to func UIView!.addConstraints(_ constraints: NSArray<Dynamic<NSLayoutConstraint!>>!)
	}

the NRE I cannot comment ton without full context, that could be anything.

(RemObjects) #7

bugs://82460 got closed with status fixed.

1 Like
(wdb) #8

I can confirm I can compile this code now

(wdb) #9

It’s compiling now!

Only still getting this issue and I am seem to be unable to set a breakpoint before where I am appending the customConstraints-array as then the app in the simulator gets stuck and nothing happens. I am happy to show what’s going on over screen sharing.

(marc hoffman) #10

can you add logging & check logcat?

(wdb) #11

Hmm, I think I might found the potential issue. Not 100% sure but when I instead of using the += operator actually use append I am getting the following compiler error:

E: Parameter 1 is "NSArray<Dynamic<NSLayoutConstraint!>>", should be "NSLayoutConstraint!", in call to func Swift.Array<NSLayoutConstraint!>.append(_ newElement: NSLayoutConstraint!) [/Users/x/Development/Projects/x/x/version-3/config-app/x/Views/TextFieldCell.swift (182)]

My apologies looks like the NSLayoutConstraint.constraints() is returning an array and it looks like that the SwiftBaseLibrary is missing some operators like this one:
https://developer.apple.com/documentation/swift/array/2963457

Something that looks close can be found at: https://github.com/remobjects/SwiftBaseLibrary/blob/e55b9c14eaab4c46799d777d25a261f3527ab87a/Source/Array.swift#L246 but it looks like it’s not working?

If I try the following count in the Playground in Xcode:

var items = [Int]()
var item1 = 2
items += [1,3,4]
items += [item1]
print(items)

it’s rendering:

[1, 3, 4, 2]
(wdb) #12

If I change my code to dynamicConstraints = dynamicConstraints + NSLayoutConstraint.constraints(visualFormat: "H:|-[textField]-|", options: .alignAllLeft, metrics: nil, views: views) it’s working fine.

Looks like the operator overload for += is missing :slight_smile:
Not sure why this code wouldn’t fail compiler time though

(marc hoffman) #13

Hmm, this works fine for me:

import Foundation

print("The magic happens here.")

let a = [1,2,3]
let b = [4,5,6]
let c = a+b

writeLn("c \(c)")
~> Process ConsoleApplication405 started
The magic happens here.
c (
    1,
    2,
    3,
    4,
    5,
    6
)
~> Process ConsoleApplication405 terminated with exit code 0

and I don’t see += implemented as operator for Arrays.

1 Like
(marc hoffman) #14

Actually, reproduced. it seems the compiler infers += from +, but does it wrong.

1 Like
(RemObjects) #15

Thanks, logged as bugs://82470

(wdb) #16

Awesome! Great that you were able to reproduce it! Would we be able to fix this temporary by defining our own += operator overload?

(marc hoffman) #17

i dont believe thats possible. using append() will be the best workaround.

1 Like
(RemObjects) #18

bugs://82470 got closed with status fixed.