Почему значение типа ‘UIView’ не имеет члена из ссылочной переменной UIView?

#ios #swift #optional #optional-binding

#iOS #быстрый #параметр-тип #необязательно-привязка

Вопрос:

Я хочу сослаться на переменную к определенной функции. Однако возникает ошибка, вызываемая Value of type 'UIView' has no member 'lineTo' Очевидно, что whatSelectObject переменная содержит классы, в которых существует элемент. Поэтому я использовал оператор If, «необязательная привязка». Но результаты те же самые.

 //: A UIKit based Playground for presenting user interface

import UIKit
import PlaygroundSupport

class ObjectView: UIView {
    var outGoingLine : CAShapeLayer?
    var inComingLine : CAShapeLayer?

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func lineTo(connectToObj: ObjectView) -> CAShapeLayer {
        let path = UIBezierPath()
        path.move(to: CGPoint(x: self.frame.maxX, y: self.frame.midY))
        path.addLine(to: CGPoint(x: connectToObj.frame.minX, y: connectToObj.frame.midY))

        let line = CAShapeLayer()
        line.path = path.cgPath
        line.lineWidth = 5
        line.fillColor = UIColor.clear.cgColor
        line.strokeColor = UIColor.gray.cgColor
        connectToObj.inComingLine = line
        outGoingLine = line
        return line
    }
}


class MyViewController : UIViewController {
    var whatSelectView: UIView?
    override func loadView() {
        let view = UIView()
        view.backgroundColor = .white

        let object = ObjectView(frame: CGRect(x: 10, y: 100, width: 100, height: 100))
        object.backgroundColor = UIColor.orange
        view.addSubview(object)

        whatSelectView = object

        let object2 = ObjectView(frame: CGRect(x: 200, y: 200, width: 100, height: 100))
        object2.backgroundColor = UIColor.red
        view.addSubview(object2)

        if let s = whatSelectView {
            view.layer.addSublayer(s.lineTo(connectToObj: object2)) // error
        }

        self.view = view
    }
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()
  

!Этот код является примером сокращенного кода, о котором идет речь, чтобы помочь респонденту понять его.
Я могу ссылаться непосредственно на object переменную, но я должен ссылаться на whatSelectView в обязательном порядке.

Почему это приводит к ошибке в ссылочной переменной? Или я ошибся с необязательной привязкой?

Комментарии:

1. if let s = whatSelectView as? ObjectView вместо if let s = whatSelectView . Потому что для компилятора whatSelectView это UIView (как указано в получаемой вами ошибке), поэтому id не знает lineTo(connectToObj:) . Сообщите компилятору с приведением, что это на самом деле ObjectView объект, поэтому он знает этот метод.

2. @Larme Спасибо за ваш первый хороший ответ на вопрос.

Ответ №1:

Действительно, в UIView нет ни элемента, ни вызываемого метода lineTo , и вам приходится использовать приведение ( as? в вашем случае)

вот так:

 if let s = whatSelectView as? ObjectView {
     view.layer.addSublayer(s.lineTo(connectToObj: object2)) // error
}
  

Кроме того, ссылка на whatSelectView должна быть слабой, потому что view уже содержит сильную ссылку на него, поскольку его объект является вложенным представлением.

И вам вообще не нужно условие if, у вас уже есть ссылка на представление с использованием object.

Итак, вот мое предложение по лучшей реализации

 class MyViewController : UIViewController {
    weak var whatSelectView: ObjectView?

    override func loadView() {
        let view = UIView()
        view.backgroundColor = .white

        let object = ObjectView(frame: CGRect(x: 10, y: 100, width: 100, height: 100))
        object.backgroundColor = UIColor.orange
        view.addSubview(object)

        whatSelectView = object

        let object2 = ObjectView(frame: CGRect(x: 200, y: 200, width: 100, height: 100))
        object2.backgroundColor = UIColor.red
        view.addSubview(object2)

        let shape = object.lineTo(connectToObj: object2)
        view.layer.addSublayer(shape)

        self.view = view
    }
}
  

Комментарии:

1. Спасибо за ваш подробный ответ. Вы сообщили мне, что есть два способа.

Ответ №2:

 if let s = whatSelectView as? ObjectView {
   view.layer.addSublayer(s.lineTo(connectToObj: object2))
}
  

это должно решить вашу проблему.

Ответ №3:

Изменить

 var whatSelectView: UIView?
  

Для

 var whatSelectView: ObjectView?
  

и оно будет скомпилировано. Как сказал @Larme, когда вы объявляете его как простое UIView , вы не можете получить доступ к каким-либо элементам и функциям, которые находятся в подклассах UIView .

Комментарии:

1. Спасибо за ваш искренний ответ и предложение.