在Swift中从不同的类访问ViewController中的对象 [英] Access objects in ViewController from a different class in Swift

查看:717
本文介绍了在Swift中从不同的类访问ViewController中的对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个ViewController UIView名为 myView 和UIImageView名为 myImageView 。在下面的代码中,我有一个类名为 viewLine ,它附加到名为 myView 的UIView。



我遇到的麻烦是当 touchesEnded 被调用时,我想更改 myImageView 在ViewController。当我尝试这个时,不会改变 myImageView 的alpha。



通过将 viewLine 类移动到主ViewController中来实现这一点,出现以下错误 - override func drawRect(rect:CGRect) - 方法不会覆盖其超类中的任何方法 self.setNeedsDisplay() - 类型ViewController的值没有成员'setNeedsDisplay'。)



问题



< > 1 - 如何修改名为 viewLine 的类中的代码以访问ViewController storyboard上的其他UI对象或函数,例如 myImageView ?即如何在之后改变 viewLine 类中的 myImageView code>被调用?



2 - 我有一个滑块 sliderLineSize 在ViewController和一个变量 lineSize 在ViewController。 UISlider sliderLineSize 更改 lineSize 。但是,在 viewLine drawRect 部分中使用 lineSize >类。
如何传递或访问类中的ViewController中的变量集



(3 - viewLine 类放入主ViewController?)

  import UIKit 

class ViewController:UIViewController {

@IBOutlet weak var myView:UIView!
@IBOutlet weak var myImageView:UIImageView!

var lineSize:Int = 1

override func viewDidLoad(){
super.viewDidLoad()
}

override func didReceiveMemoryWarning(){
super.didReceiveMemoryWarning()
}

override func touchesEnded(touches:Set< UITouch> withEvent event:UIEvent?){
myImageView.alpha = 0.5
}

@IBAction func sliderLineSize(sender:UISlider){
lineSize = Int(sender.value)
}

}

class viewLine:UIView {

let path = UIBezierPath()
var incrementalImage:UIImage?
var previousPoint:CGPoint = CGPoint.zero
var strokeColor:UIColor?

需要init?(coder aDecoder:NSCoder){
super.init(coder:aDecoder)
}

override func drawRect ){
incrementImage?.drawInRect(rect)
path.lineWidth = lineSize
path.stroke()
}

override func touchesBegan(touches:设置< UITouch> ;, withEvent事件:UIEvent?){
let touch:AnyObject? = touches.first
let currentPoint = touch!.locationInView(self)
path.moveToPoint(currentPoint)
previousPoint = currentPoint
self.setNeedsDisplay()
}

override func touchesMoved(touches:Set< UITouch> ;, withEvent event:UIEvent?){
let touch:AnyObject? = touches.first
let currentPoint = touch!.locationInView(self)
let midPoint = self.midPoint(previousPoint,p1:currentPoint)
path.addQuadCurveToPoint(midPoint,controlPoint:previousPoint)
previousPoint = currentPoint
path.moveToPoint(midPoint)
self.setNeedsDisplay()
}

override func touchesEnded(touches:Set< UITouch> withEvent事件:UIEvent?){
self.drawBitmap()
self.setNeedsDisplay()
path.removeAllPoints()
}

func midPoint :CGPoint,p1:CGPoint) - > CGPoint {
let x =(p0.x + p1.x)/ 2
let y =(p0.y + p1.y)/ 2
return CGPoint(x:x,y:y)
}

func drawBitmap(){
UIGraphicsBeginImageContextWithOptions(self.bounds.size,true,1)
strokeColor?.setStroke()
if((incrementalImage)== nil){
let rectPath:UIBezierPath = UIBezierPath(rect:self.bounds)
UIColor.whiteColor()。setFill )
rectPath.fill()
}
incrementalImage?.drawAtPoint(CGPointZero)
path.stroke()
incrementalImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext )
}

}


解决方案

我查了一下如何从它的子视图引用一个ViewController,我发现是一个StackOverflow答案说:遵循MVC模式,一个ViewController知道它的视图,但视图不应该知道ViewController 。相反,你应该声明委托协议(来源: Swift - 如何将视图控制器的引用传递给一个子UIView类?)



所以,我虽然解决方案是写一个自定义委托协议,并使ViewController遵守它上述答案中的代码是有点过时的写委托协议,但问题的开始 Pure Swift类符合静态方法协议 - 上行问题显示如何正确编写协议



我的storyboard有这样的图:




  • 查看


    • 我的视图(链接到您的代码)

    • 我的图片视图

      我已重命名类 viewLine


code>到 ViewLineUIView ,因为我认为这将是一个更具描述性的基础超类的名称。代码如下。



代码:

  import UIKit 

protocol ViewLineUIViewDelegate:class {
func onTouchesEnded(viewLine:ViewLineUIView)
}

class ViewController:UIViewController,ViewLineUIViewDelegate {

@IBOutlet weak var myView:UIView!
@IBOutlet weak var myImageView:UIImageView!
@IBOutlet weak var sliderValue:UISlider!

var viewLineDelegate:ViewLineUIView!

override func viewDidLoad(){
super.viewDidLoad()
viewLineDelegate = myView as? ViewLineUIView
viewLineDelegate!.delegate = self

//将lineWidth更新为滑块的初始值
updateLineWidth()
}

override func didReceiveMemoryWarning(){
super.didReceiveMemoryWarning()
}

func onTouchesEnded(viewLine:ViewLineUIView){
myImageView!.alpha = 0.5
}

//更新行宽度!
@IBAction func onSliderChange(sender:UISlider){
updateLineWidth()

}

func updateLineWidth(){
let drawView = myView as! ViewLineUIView
//你可以将这个10值改为你的最大值lineWidth
drawView.path.lineWidth = CGFloat(sliderValue.value * 10)
print(New value is:+ String(drawView.path.lineWidth))
}


}

类ViewLineUIView:UIView {

weak var delegate:ViewLineUIViewDelegate?

let path = UIBezierPath()
var incrementalImage:UIImage?
var previousPoint:CGPoint = CGPoint.zero
var strokeColor:UIColor?

需要init?(coder aDecoder:NSCoder){
//初始化lineWidth,以便编译器不会抱怨
super.init(coder:aDecoder)
}

override func drawRect(rect:CGRect){
incrementalImage?.drawInRect(rect)
path.stroke()
}

覆盖func touchesBegan(触摸:设置< UITouch>,withEvent事件:UIEvent?){
let touch:AnyObject? = touches.first
let currentPoint = touch!.locationInView(self)
path.moveToPoint(currentPoint)
previousPoint = currentPoint
self.setNeedsDisplay()
}

override func touchesMoved(touches:Set< UITouch> ;, withEvent event:UIEvent?){
let touch:AnyObject? = touches.first
let currentPoint = touch!.locationInView(self)
let midPoint = self.midPoint(previousPoint,p1:currentPoint)
path.addQuadCurveToPoint(midPoint,controlPoint:previousPoint)
previousPoint = currentPoint
path.moveToPoint(midPoint)
self.setNeedsDisplay()
}

override func touchesEnded(touches:Set< UITouch> withEvent事件:UIEvent?){
self.drawBitmap()
self.setNeedsDisplay()
path.removeAllPoints()

委托?.onTouchesEnded $ b}

func midPoint(p0:CGPoint,p1:CGPoint) - > CGPoint {
let x =(p0.x + p1.x)/ 2
let y =(p0.y + p1.y)/ 2
return CGPoint(x:x,y:y)
}

func drawBitmap(){
UIGraphicsBeginImageContextWithOptions(self.bounds.size,true,1)
strokeColor?.setStroke()
if((incrementalImage)== nil){
let rectPath:UIBezierPath = UIBezierPath .bounds)
UIColor.whiteColor()。setFill()
rectPath.fill()
}
incrementalImage?.drawAtPoint(CGPointZero)
path.stroke
incrementImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}

}

正如你所看到的,编辑路径的lineWidth是很简单的,你不需要创建另一个委托协议。 ViewController可以直接访问其子视图。你应该知道需要演员。


I have a ViewController with a UIView named myView and a UIImageView named myImageView. In the code below, I have a class named viewLine which is attached to the UIView named myView.

The trouble I am having is when touchesEnded is called, I want to change the alpha of myImageView inside the ViewController. When I try this, no changes to the the alpha of myImageView occur.

(Alternatively, when I try to achieve this by moving the viewLine class into the main ViewController, the following errors present - override func drawRect(rect: CGRect) - Method does not override any method from its superclass and self.setNeedsDisplay() - Value of type 'ViewController' has no member 'setNeedsDisplay’.)

Questions:

1 - How do I modify the code in the class named viewLine to access other UI objects or functions on the ViewController storyboard such as myImageView? i.e. How do I change the alpha of myImageView from the class named viewLine after touchesEnded is called?

2 - I have a slider sliderLineSize in the ViewController and a variable lineSize in the ViewController. The UISlider sliderLineSize changes lineSize. However, lineSize is used in the drawRect section of the viewLine class. How do I pass or make accessible the variable set in the ViewController in the class?

(3 - How do instead incorporate the viewLine class into the main ViewController?)

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var myView: UIView!
    @IBOutlet weak var myImageView: UIImageView!

    var lineSize: Int = 1

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        myImageView.alpha = 0.5
    }

    @IBAction func sliderLineSize(sender: UISlider) {
        lineSize = Int(sender.value)
    }

}

class viewLine: UIView {

    let path=UIBezierPath()
    var incrementalImage:UIImage?
    var previousPoint:CGPoint = CGPoint.zero
    var strokeColor:UIColor?

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func drawRect(rect: CGRect) {
            incrementalImage?.drawInRect(rect)
            path.lineWidth = lineSize
            path.stroke()
    }

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        let touch: AnyObject? = touches.first
        let currentPoint = touch!.locationInView(self)
        path.moveToPoint(currentPoint)
        previousPoint=currentPoint
        self.setNeedsDisplay()
    }

    override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
        let touch: AnyObject? = touches.first
        let currentPoint = touch!.locationInView(self)
        let midPoint = self.midPoint(previousPoint, p1: currentPoint)
        path.addQuadCurveToPoint(midPoint,controlPoint: previousPoint)
        previousPoint=currentPoint
        path.moveToPoint(midPoint)
        self.setNeedsDisplay()
    }

    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        self.drawBitmap()
        self.setNeedsDisplay()
        path.removeAllPoints()
    }

    func midPoint(p0:CGPoint,p1:CGPoint)->CGPoint {
        let x=(p0.x+p1.x)/2
        let y=(p0.y+p1.y)/2
        return CGPoint(x: x, y: y)
    }

    func drawBitmap() {
        UIGraphicsBeginImageContextWithOptions(self.bounds.size, true, 1)
        strokeColor?.setStroke()
        if((incrementalImage) == nil){
            let rectPath:UIBezierPath = UIBezierPath(rect: self.bounds)
            UIColor.whiteColor().setFill()
            rectPath.fill()
        }
        incrementalImage?.drawAtPoint(CGPointZero)
        path.stroke()
        incrementalImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
    }

}

解决方案

I looked up about how to reference a ViewController from its subview and the best bet I found was a StackOverflow answer saying "Following the MVC pattern, a ViewController knows about its Views, but the View shouldn't know about the ViewController. Instead you should declare delegate protocol" (Source: Swift - How to pass a view controller's reference to a sub UIView class?)

So, I though the solution would be to write a custom delegate protocol and make the ViewController abide by it. The code in the aforementioned answer is a bit outdated to write the delegate protocol, but the beginning of the question in Pure Swift class conforming to protocol with static method - issue with upcasting shows how to write a protocol properly that works in my Xcode 7.2.

My storyboard has a diagram like this:

  • View
    • My View (linked to your code)
    • My Image View (background is a static image I chose)

I renamed the class viewLine to ViewLineUIView as I thought it would be a more descriptive name of the underlying superclass. The code is below.

Code:

import UIKit

protocol ViewLineUIViewDelegate: class {
    func onTouchesEnded(viewLine: ViewLineUIView)
}

class ViewController: UIViewController, ViewLineUIViewDelegate {

    @IBOutlet weak var myView: UIView!
    @IBOutlet weak var myImageView: UIImageView!
    @IBOutlet weak var sliderValue: UISlider!

    var viewLineDelegate: ViewLineUIView!

    override func viewDidLoad() {
        super.viewDidLoad()
        viewLineDelegate = myView as? ViewLineUIView
        viewLineDelegate!.delegate = self

        //update lineWidth to initial value of slider
        updateLineWidth()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    func onTouchesEnded(viewLine: ViewLineUIView) {
        myImageView!.alpha = 0.5
    }

    //Updating lineWidth!
    @IBAction func onSliderChange(sender: UISlider) {
        updateLineWidth()

    }

    func updateLineWidth() {
        let drawView = myView as! ViewLineUIView
        //you can change this "10" value to your max lineWidth
        drawView.path.lineWidth = CGFloat(sliderValue.value*10)
        print("New value is: " + String(drawView.path.lineWidth))
    }


}

class ViewLineUIView: UIView {

    weak var delegate: ViewLineUIViewDelegate?

    let path=UIBezierPath()
    var incrementalImage:UIImage?
    var previousPoint:CGPoint = CGPoint.zero
    var strokeColor:UIColor?

    required init?(coder aDecoder: NSCoder) {
        //Initialize lineWidth so that compiler doesn't complain
        super.init(coder: aDecoder)
    }

    override func drawRect(rect: CGRect) {
        incrementalImage?.drawInRect(rect)
        path.stroke()
    }

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        let touch: AnyObject? = touches.first
        let currentPoint = touch!.locationInView(self)
        path.moveToPoint(currentPoint)
        previousPoint=currentPoint
        self.setNeedsDisplay()
    }

    override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
        let touch: AnyObject? = touches.first
        let currentPoint = touch!.locationInView(self)
        let midPoint = self.midPoint(previousPoint, p1: currentPoint)
        path.addQuadCurveToPoint(midPoint,controlPoint: previousPoint)
        previousPoint=currentPoint
        path.moveToPoint(midPoint)
        self.setNeedsDisplay()
    }

    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        self.drawBitmap()
        self.setNeedsDisplay()
        path.removeAllPoints()

        delegate?.onTouchesEnded(self)
    }

    func midPoint(p0:CGPoint,p1:CGPoint)->CGPoint {
        let x=(p0.x+p1.x)/2
        let y=(p0.y+p1.y)/2
        return CGPoint(x: x, y: y)
    }

    func drawBitmap() {
        UIGraphicsBeginImageContextWithOptions(self.bounds.size, true, 1)
        strokeColor?.setStroke()
        if((incrementalImage) == nil){
            let rectPath:UIBezierPath = UIBezierPath(rect: self.bounds)
            UIColor.whiteColor().setFill()
            rectPath.fill()
        }
        incrementalImage?.drawAtPoint(CGPointZero)
        path.stroke()
        incrementalImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
    }

}

As you can see, editing the lineWidth of the path is straightforward and you don't need to create another delegate protocol. The ViewController can access its subviews directly. You should just be aware that a cast is needed.

这篇关于在Swift中从不同的类访问ViewController中的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆