Swift转Objective-C后遇类型错误求解决:NSArray?.Type不遵循Sequence协议
Hey there! Let's walk through what's causing this error in your Swift code and fix it up to match the behavior of your original Objective-C implementation.
First, let's break down the issues in your current Swift code:
- Incorrect variable declaration:
var panels = NSArray?isn't how you declare an optionalNSArrayin Swift. That syntax is invalid—you need to usevar panels: NSArray?instead. Even better, use Swift's native array type[UIView]?for type safety (since your panels are allUIViewinstances). - Trying to iterate over an optional array:
panelsis an optional (NSArray?), so the compiler can't confirm it has a value to iterate over. You need to safely unwrap it first. - Unsafe type handling:
NSArraystores elements asAny, so you can't directly treat them asUIViewwithout casting. - Optional value in arithmetic:
panel?.frame.widthreturns an optionalCGFloat?, which can't be directly added to a non-optionalCGFloatvariable.
Fix 1: Using NSArray (matching your Objective-C setup)
Here's the corrected code using NSArray, with safe unwrapping and type casting:
// Correct optional NSArray declaration var panels: NSArray? func buttonTotalWidth() -> CGFloat { var width: CGFloat = 0 // Safely unwrap the optional panels array guard let unwrappedPanels = panels else { return width // Return 0 if panels is nil } for item in unwrappedPanels { // Cast each item to UIView safely before accessing its frame if let panel = item as? UIView { width += panel.frame.width } } return width }
Fix 2: Using Swift Native Array (Recommended)
Swift's native arrays are type-safe and more idiomatic. This version avoids casting and feels more natural in Swift:
// Optional array of UIView instances (type-safe!) var panels: [UIView]? func buttonTotalWidth() -> CGFloat { var width: CGFloat = 0 // Unwrap the array and iterate if let unwrappedPanels = panels { for panel in unwrappedPanels { width += panel.frame.width } } return width }
Bonus: Concise Swift Version with reduce
You can even condense this into a single line using Swift's reduce method, which is perfect for calculating a total from a collection:
var panels: [UIView]? func buttonTotalWidth() -> CGFloat { // Unwrap panels, reduce to sum widths, or return 0 if panels is nil panels?.reduce(0.0) { total, panel in total + panel.frame.width } ?? 0.0 }
Why your Objective-C code worked
In Objective-C, self.panels (even as a plain NSArray*) will silently skip iteration if it's nil, and the compiler assumes elements are UIView* based on your usage. Swift is stricter about optionals and type safety, so we need to explicitly handle those cases.
内容的提问来源于stack exchange,提问作者Siva

