为啥这个 Swift Playground 打印和循环两次?

Posted

技术标签:

【中文标题】为啥这个 Swift Playground 打印和循环两次?【英文标题】:Why is this Swift Playground Printing & Looping Twice?为什么这个 Swift Playground 打印和循环两次? 【发布时间】:2017-08-07 06:09:35 【问题描述】:

我不明白为什么for 循环和我打印的所有内容都在重复。

我本可以发誓在我编写for 循环之前他们没有这样做,但我尝试重新启动 Xcode;将代码复制到新的游乐场;注释掉最后几行;和谷歌搜索——无济于事。

prints 在显然被第二次执行之前都被执行了一次的事实让我觉得不知何故整个事情被调用了两次,也许这也可以解释循环,但我只是不明白如何这可能正在发生。

我正在运行 Xcode 8.3.3 (8E3004b)(不是开发版本)。

这是代码,下面是我得到的截图

//: I don't see why it's printing everything twice, or why the for loop is looping twice

import UIKit
import PlaygroundSupport


class CustomView: UIView 

    let pathCG: [CGPoint] = [CGPoint(x:50, y:300), CGPoint(x:100, y:350), CGPoint(x:230, y:350), CGPoint(x:230, y:120)]

    override func draw(_ rect: CGRect) 

        print("what the hell")
        print(pathCG)
        print(pathCG.dropLast().count)

        for v in 0...pathCG.dropLast().count 
            let segAngle = vecDirCG(vec: [pathCG[v], pathCG[(v+1) % 4]]) * 180/CGFloat.pi
        
    

    // MARK: get direction given two points
    func vecDirCG(vec: [CGPoint]) -> CGFloat 
        return atan2(-vec[1].y + vec[0].y, vec[1].x - vec[0].x)
    


let containerView = CustomView(frame: CGRect(x: 0, y: 0, width: 250, height: 600))
containerView.backgroundColor = UIColor.orange

PlaygroundPage.current.liveView = containerView

编辑:这是接受@MohammadSadiq 的回答后的更新。它摆脱了双重打印,但双重循环似乎仍然存在。但是,更改pathCGCGPoint 的值只会更改循环的第一个 结果,而不是第二个。现在我注意到注释掉原始游乐场中的container.backgroundColor已经修复了(明显的)重复执行(循环的),所以我认为这是某种缓存问题。

【问题讨论】:

因为 draw 调用是这样工作的,所以你无法确定调用它的时间和频率,这就是为什么你不应该在渲染中执行任何业务逻辑。 【参考方案1】:

关于override func draw(_ rect: CGRect)

第一次显示视图或发生事件时调用此方法 发生使视图的可见部分无效。

你的线路

containerView.backgroundColor = UIColor.orange

可能导致 draw 得到另一个调用。

【讨论】:

是的,其他人有一个答案(他们删除了)说删除该行并将self.backgroundColor = .orange 放入函数中(我也尝试过... = UIColor.orange),这确实修复了双重打印(尽管self... 部分似乎不起作用),但它似乎仍然执行了两次 for 循环。 我测试过了。它不断变化的背景导致抽奖得到另一个调用。因此 for 循环打印两次。那是你的问题,这就是答案。你能澄清一下你还想问什么吗? @Cody,你如何确认它似乎仍然执行了两次 for 循环? for 循环中没有print draw() 被调用了两次。 @Cody,不要依赖价值历史。它不能很好地清除先前的输出。顺便问一下,如果你的draw(_:) 打了两次电话会有什么问题?【参考方案2】:

正如 luk2302 已经评论的那样,在实际应用程序中,很难预测何时或多少次调用 draw(_:)。而且 Playground 不是探索draw(_:) 行为的好地方。

在操场上:

import UIKit
import PlaygroundSupport

class CustomView: UIView 

    let pathCG: [CGPoint] = [CGPoint(x:50, y:300), CGPoint(x:100, y:350), CGPoint(x:230, y:350), CGPoint(x:230, y:120)]

    override func draw(_ rect: CGRect) 

        print(pathCG)

        for v in pathCG.indices 
            let segAngle = vecDirCG(vec: [pathCG[v], pathCG[(v+1) % pathCG.count]]) * 180 / .pi
        
    

    // MARK: get direction given two points
    func vecDirCG(vec: [CGPoint]) -> CGFloat 
        return atan2(-vec[1].y + vec[0].y, vec[1].x - vec[0].x)
    


let containerView = CustomView(frame: CGRect(x: 0, y: 0, width: 250, height: 600))
print("---------- CustomView created ----------")
containerView.backgroundColor = .orange
print("---------- backgroundColor set ----------")
PlaygroundPage.current.liveView = containerView
print("---------- liveView set ----------")

输出:

draw [(50.0, 300.0), (100.0, 350.0), (230.0, 350.0), (230.0, 120.0)]
---------- CustomView created ----------
draw [(50.0, 300.0), (100.0, 350.0), (230.0, 350.0), (230.0, 120.0)]
---------- backgroundColor set ----------
---------- liveView set ----------

似乎draw(_:) 被调用了两次,

创建视图的新实例时 修改backgroundColor属性时

但您不应认为这种行为与实际应用中的行为相同。


在单一视图应用中:

import UIKit

class ViewController: UIViewController 

    override func viewDidLoad() 
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        let containerView = CustomView(frame: CGRect(x: 0, y: 0, width: 250, height: 600))
        print("---------- CustomView created ----------")
        containerView.backgroundColor = .orange
        print("---------- backgroundColor set ----------")
        self.view!.addSubview(containerView)
        print("---------- addSubview finished ----------")
    



class CustomView: UIView 

    let pathCG: [CGPoint] = [CGPoint(x:50, y:300), CGPoint(x:100, y:350), CGPoint(x:230, y:350), CGPoint(x:230, y:120)]

    override func draw(_ rect: CGRect) 

        print(#function, pathCG)

        for v in pathCG.indices 
            let segAngle = vecDirCG(vec: [pathCG[v], pathCG[(v+1) % pathCG.count]]) * 180 / .pi
        
    

    // MARK: get direction given two points
    func vecDirCG(vec: [CGPoint]) -> CGFloat 
        return atan2(-vec[1].y + vec[0].y, vec[1].x - vec[0].x)
    

输出:

---------- CustomView created ----------
---------- backgroundColor set ----------
---------- addSubview finished ----------
draw [(50.0, 300.0), (100.0, 350.0), (230.0, 350.0), (230.0, 120.0)]

draw(_:) 仅在 addSubview 完成后调用一次。 (其实在上面的代码中,是在viewDidLoad完成之后调用的。)


Playground 保留了一些中间结果。对于UIViews,它会保留绘制的结果。 (这会导致draw(_:)被调用。)但是在实际应用中,这种中间结果是不会被保留的,所以draw(_:)可能不会在相同的位置被调用。

【讨论】:

以上是关于为啥这个 Swift Playground 打印和循环两次?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Swift Playground 打印到控制台?

尝试在 Swift Playground 中打印函数时出现 EXC_BAD_INSTRUCTION 错误

swift 在控制台中打印所有可用字体。尝试在Xcode Playground中粘贴此代码。

Swift 3 Playground 以本地格式记录日期。如何?

在 xCode Playground 上打印 /n [重复]

Swift PlayGround无限Running问题