Swift 从主视图控制器中提取@IBOutlets属性值

Swift 从主视图控制器中提取@IBOutlets属性值,swift,subclassing,Swift,Subclassing,从一开始,我就一直在使用MVP模型,以保持工作正常进行,但几个月后的今天,我意识到我的大多数项目都有“大型视图控制器”。扩展起初很好地整理了实际的视图控制器文件,但从技术上讲,代码仍然在视图控制器中 对于我的问题,一个更实际的方法是在我的上一个项目中,我进行了一次应用内购买,之后用户解锁了一些新功能。我们假设整个StoreKit逻辑正在发挥作用,购买已成功完成,您即将向用户提供新功能 为了处理这个问题,我在主视图控制器(PreferencesViewController)中有一个函数func u

从一开始,我就一直在使用MVP模型,以保持工作正常进行,但几个月后的今天,我意识到我的大多数项目都有“大型视图控制器”。扩展起初很好地整理了实际的视图控制器文件,但从技术上讲,代码仍然在视图控制器中

对于我的问题,一个更实际的方法是在我的上一个项目中,我进行了一次应用内购买,之后用户解锁了一些新功能。我们假设整个StoreKit逻辑正在发挥作用,购买已成功完成,您即将向用户提供新功能

为了处理这个问题,我在主视图控制器(
PreferencesViewController
)中有一个函数
func unlockFeatures
),当成功进行应用内购买时,该函数由和观察者触发

class PreferencesViewController: UIViewController {

    ...
    @obc func unlockFeatures {
        InAppPuchaseButton.isEnabled = false
        InAppPuchaseButton.applyOpacity(opacity: 1.0)
    }
    ...
}
在这一点上,当我只需要启用和更改一个按钮的不透明度时,一切看起来都很干净。我的问题是如何处理
func unlockFeatures
中的情况,您需要像这样处理多行UI代码:

class PreferencesViewController: UIViewController {

    ...
    @obc func unlockFeatures {
        InAppPuchaseButton.isEnabled = false
        InAppPuchaseButton.applyOpacity(opacity: 1.0)
        InAppPuchaseButton.isHidden = false
        RefreshLabel.text = "DOWNLOADING EVENTS"
        self.activityIndicator.stopAnimating()
        //And keep going for 50 lines more of code!!
    }
    ...
}

对我来说,它看起来很混乱,我想在
首选项viewcontroller
之外提取这个函数,并在需要时调用它。有没有办法在view controller类之外提取所有这些UI逻辑,或者这是一种不好的做法?

应用内购买示例是一个很好的例子。这里我们要做的是提供一个单一的集中式对象,它可以(例如):

  • 充当不涉及接口的IAP相关代码的位置,例如充当SKPaymentTransactionObserver

  • 充当应用程序其余部分的网关,以询问用户是否已购买(当然,我们的对象将通过咨询用户默认值知道答案,但这将是其公共API隐藏的实现细节)

将这些功能与视图控制器断开是有意义的,因为它们与控制任何视图无关

因此,这是使用helper类的绝佳机会。一个典型的实现是分配一个单例实例的类,我们获取并存储在应用程序委托或根视图控制器的属性中,这两个属性都是持久的,并且很容易从应用程序中的任何位置访问


在更广泛的上下文中,我一直使用这种类型的helper对象,以准确地解决您描述的问题。例如,在一个游戏应用程序中,我在主视图控制器中有很多代码,直到我将几个操作区域拆分为助手类,因为它们实际上与视图的控制无关。例如,计时器的逻辑和分数的维护进入了helper对象。当我们进入游戏的下一阶段时,决定下一步要做什么的“状态机”进入了一个helper对象。等等


在你修改后的问题中,你说:

对我来说,它看起来很混乱,我想在PreferencesViewController之外提取这个函数,并在需要时调用它。有没有办法在视图控制器类之外提取所有这些UI逻辑,或者这是一种不好的做法


这里没有“杂乱”的东西;这一切都在一个函数中,这是正确的。好的做法是将UI操作放在view controller类中,但也可能从其他地方调用它(例如,由我在回答中描述的助手调用)。实际上我要做的是让助手发布一个通知,这样它就不知道会发生什么;它只是喊“好的,用户购买了!”视图控制器收到通知并调用该方法。

Hi@BES!嗨@ctietze!现在我将编辑我的问题,以便更深入地了解我的意思。顺便说一句,我得到的错误是“(lldb)”。谢谢您的回答。请参阅我对您的编辑做出的修改后的回答。当您在Xcode控制台中看到
(lldb)
时,这是命令提示符,您可以在其中输入lldb命令,如
po self
,以打印对象描述等。实际错误可能是在之前打印的,如果不是,则是一个一般运行时异常,Xcode在源代码中以红色功能区显示,并带有“EXC_something`右侧的错误代码。@matt在我的问题更新后所做的修改就是我想要的澄清。我不知道将UI放在view controller类中是一种好的做法。谢谢你会注意到我这里说的是一个helper类而不是一个struct。理想情况下,我更喜欢结构,但在许多情况下,当我们需要Objective-C与我们交谈,或者我们将要进行大量的变异时,结构太麻烦了。当然,我已经让整个商店逻辑运行良好,并将其保存在静态变量中,无论购买与否。我担心的是,就在这个时间点之后,您必须向用户交付新功能。例如,提供这些新功能可以在UI上启用在进行应用内购买之前已禁用的UI按钮。如何对实际的UIButton.isEnabled=true进行子类化?我不知道“子类”与任何事情都有什么关系。这个故事中没有子类。我也不明白你的问题是什么。帮助者的工作不是实现任何事情;这是视图控制器的工作。助手的工作是在用户购买时发出用户已购买的信号,并按需报告用户已购买。你是对的@matt我知道助手的工作是什么,在我的应用程序中工作正常。我没有看到的是如何处理“启用作业”(必须由视图控制器完成)包含50多行代码的情况。有没有办法将其子类化,以便从视图控制器中删除这50行?您一直在使用“子类”这个词。我