0

I have an issue using Swift. I have a class:

class ClassA : UIView{

    override public init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    init(from uiview: UIView) {
        super.init(frame: .zero)
    }

}

Then I have another class PageViewer

class PageViewer: UIView{

    var values : [ClassA]?
    var location: Int = 0

    public func test(){
        for i in 0..<values!.count {
            location = i
            values![i] = self.subviews[location] as! ClassA
        }
    }
}

problem: I'm trying to add UIViews as sub-views to the pageviewer but I'm getting a run time exception on this line values![i] = self.subviews[location] as! ClassA saying Could not cast value of type 'UIView' to 'MyTestApp.ClassA. I want to know if there is a possible workaround for this.

EinStyn
  • 81
  • 7
  • 1
    *Are* all subviews `ClassA` instances? – luk2302 Aug 14 '23 at 13:22
  • 1
    Make sure that all subviews of `PageViewer` are of type `ClassA` – Shehata Gamal Aug 14 '23 at 13:23
  • 1
    There may be other sub views of your `PageViewer` that aren't instances of `ClassA`. Every time you use ! to force downcast or force unwrap you risk a crash. Also, what if there are more elements in `values` that you have subviews? You are going to get an array bounds crash. You say you are trying to add subviews, but this code isn't doing that. It is accessing subviews. A better approach would be to iterate `self.subviews` and where you get an instance of `ClassA`, append it to the array. – Paulw11 Aug 14 '23 at 13:23
  • No, they're not they're UIViews but ClassA is a subtype of UIView so I guess the casting should work or there could at least be a workaround – EinStyn Aug 14 '23 at 13:25
  • 1
    No, the cast won't work ,there is no relation between your current subclass `ClassA` and the subviews you add to the pager – Shehata Gamal Aug 14 '23 at 13:26
  • 1
    If I give you any fruit can you just assume it is an apple because apples are fruits? Obviously not. – luk2302 Aug 14 '23 at 13:28
  • 1
    When you have a bag of Animals filled with cats and dogs, and you pull out a dog, you cannot just yell at it (as!) to get it to be a cat. – Rob Napier Aug 14 '23 at 13:29
  • 1
    *"there could at least be a workaround"* - generally no. You cannot convert a peach to an apple just because you want to. – luk2302 Aug 14 '23 at 13:30
  • Using `as!` *is* the workaround. It's how you tell the compiler you are absolutely certain what the class is, even though the compiler can't prove it. `as!` lets you work around the type-checker's limits and assert what you know is true. But there is no "work around" to make a false thing be true. What do you actually want to happen here when you pull out a UIButton? If you want to ignore it, use `as?` and ignore `nil` values. If you want to do some other behavior with it, do that. If you want to stop the program (as here), use `as!`. It's not a work around, it's just choosing what you want. – Rob Napier Aug 14 '23 at 13:36
  • Okay my bad I think I'm mistaken all subviews are instances of ClassA – EinStyn Aug 14 '23 at 14:48

1 Answers1

1

You can always cast down, but only sometimes cast up. In this case, you are saying all of the subviews can be anything; force them to be a specific view type so we can hammer them into this array. Depending on what you are trying to do, there must be a more elegant way of doing it, but if you really need a workaround, then:

self.subviews[location].forEach { subView in
    if subView is ClassA {
        values.append(subView as! ClassA)
    }
}

That should pass because is validating the subview is in fact a `CVla

cutiko
  • 9,887
  • 3
  • 45
  • 59
  • 2
    I believe you've reversed upcasting and downcasting. Upcasting is to the supertype, and is always possible. I think the code you mean is `values = subviews.compactMap { $0 as? ClassA }`. There's no need for an awkward `forEach` or `as!` here. – Rob Napier Aug 14 '23 at 14:46
  • Thanks my subviews were initially not instances of ClassA, your code helped me notice that. – EinStyn Aug 14 '23 at 14:55
  • @RobNapier yes! you are right, I phrase it that way because for inexperienced developers, the super is easier to understand as "down", because any implementation has more than the minimum of the super so the super all thought is a hierarchical parent in the inheritance tree it is a less functional version than any implementation. Hey! `compactMap` TIL TY. – cutiko Aug 14 '23 at 18:46