変数値が変化したときに関数を実行する必要があります。
labelChange
という共有変数を含むシングルトンクラスがあります。この変数の値は、Model
という別のクラスから取得されます。 2つのVCクラスがあり、そのうちの1つにはボタンとラベルがあり、2番目にはボタンしかありません。
最初のVCクラスのボタンが押されると、この関数でラベルを更新します。
func updateLabel(){
self.label.text = SharingManager.sharedInstance.labelChange
}
しかし、labelChange
の値が変更されるたびに同じメソッドを呼び出したいです。そのため、ボタンをクリックしてlabelChange
値のみを更新し、このことが発生した場合は、labelChange
の新しい値でラベルを更新します。また、2番目のVCでlabelChange
値を更新できますが、この値が変更されたときにラベルを更新できません。
おそらくプロパティが解決策かもしれませんが、その方法を誰にでも教えてくれます。
2回目の編集:
シングルトンクラス:
class SharingManager {
func updateLabel() {
println(labelChange)
ViewController().label.text = SharingManager.sharedInstance.labelChange
}
var labelChange: String = Model().callElements() {
willSet {
updateLabel()
}
}
static let sharedInstance = SharingManager()
}
最初のVC:
class ViewController: UIViewController {
@IBOutlet weak var label: UILabel!
@IBAction func Button(sender: UIButton) {
SViewController().updateMessageAndDismiss()
}
}
2番目のVC:
func updateMessageAndDismiss() {
SharingManager.sharedInstance.labelChange = modelFromS.callElements()
self.dismissViewControllerAnimated(true, completion: nil)
}
@IBAction func b2(sender: UIButton) {
updateMessageAndDismiss()
}
いくつかの改善を行いましたが、シングルトンの最初のVCクラスからラベルを参照する必要があります。したがって、シングルトンのVCのラベルを更新します。
labelChange
の値を出力すると、値が更新されており、すべて問題ありません。しかし、ラベルのその値をシングルトンから更新しようとすると、エラーが表示されます。
オプション値のアンラップ中に予期せずnilが見つかりました
エラーはシングルトンクラスの4行目を指しています。
変数labelChange
のプロパティオブザーバーを使用して、didSet
内で呼び出す関数を呼び出すことができます(または、その前に呼び出す場合はwillSet
設定されています):
class SharingManager {
var labelChange: String = Model().callElements() {
didSet {
updateLabel()
}
}
static let sharedInstance = SharingManager()
}
これは Property Observers で説明されています。
試したときになぜこれが機能しなかったのかはわかりませんが、呼び出している関数(updateLabel
)が別のクラスにあるために問題が発生している場合は、変数を追加することができますSharingManager
が呼び出されたときに呼び出す関数を格納するdidSet
クラス。この場合はupdateLabel
に設定します。
編集済み:
したがって、ViewControllerからラベルを編集する場合は、ViewControllerクラスのupdateLabel()関数でラベルを更新しますが、その関数をシングルトンクラスに格納して、呼び出す関数を認識できるようにします。
class SharingManager {
static let sharedInstance = SharingManager()
var updateLabel: (() -> Void)?
var labelChange: String = Model().callElements() {
didSet {
updateLabel?()
}
}
}
次に、呼び出したい関数があるクラスのいずれかに設定します(updateLabelが呼び出したい関数であると仮定):
SharingManager.sharedInstance.updateLabel = updateLabel
もちろん、シングルトンクラスが関数を呼び出すことができるように、その関数を担当するView Controllerがまだ存在していることを確認する必要があります。
どのView Controllerが表示されているかに応じて異なる関数を呼び出す必要がある場合、 Key-Value Observing を考慮して、特定の変数の値が変更されるたびに通知を受け取ることができます。
また、そのようなView Controllerを初期化してからView ControllerのIBOutletsをすぐに設定したくないのは、IBOutletsはビューが実際にロードされるまで初期化されないためです。既存のView Controllerオブジェクトを何らかの方法で使用する必要があります。
お役に立てれば。
label.observe(\.text, changeHandler: { (label, change) in {
// text has changed
}
これは基本的にはそうですが、ちょっとした落とし穴があります。 「observe」は、保持する必要があるNSKeyValueObservationオブジェクトを返します。 -割り当てが解除されると、それ以上の通知は届きません。それを避けるために、保持されるプロパティにそれを割り当てることができます。
var observer:NSKeyValueObservation?
// then assign the return value of "observe" to it
observer = label.observe(\.text, changeHandler: { (label, change) in {
// text has changed,
}
値が変更されたか、初めて設定されたかを確認することもできます
observer = label.observe(\.text, changeHandler: { (label, change) in {
// just check for the old value in "change" is not Nil
if let oldValue = change.oldValue {
print("\(label.text) has changed from \(oldValue) to \(label.text)")
} else {
print("\(label.text) is now set")
}
}
詳細については、Appleのドキュメントを参照してください こちら
RxSwiftを使用する別の方法があります。
RxSwiftポッドとRxCocoaポッドをプロジェクトに追加します
SharingManager
を変更します。
import RxSwift
class SharingManager {
static let sharedInstance = SharingManager()
private let _labelUpdate = PublishSubject<String>()
let onUpdateLabel: Observable<String>? // any object can subscribe to text change using this observable
// call this method whenever you need to change text
func triggerLabelUpdate(newValue: String) {
_labelUpdate.onNext(newValue)
}
init() {
onUpdateLabel = _labelUpdate.shareReplay(1)
}
}
ViewControllerでは、次の2つの方法で値の更新をサブスクライブできます。
a。更新をサブスクライブし、ラベルテキストを手動で変更する
// add this ivar somewhere in ViewController
let disposeBag = DisposeBag()
// put this somewhere in viewDidLoad
SharingManager.sharedInstance.onUpdateLabel?
.observeOn(MainScheduler.instance) // make sure we're on main thread
.subscribeNext { [weak self] newValue in
// do whatever you need with this string here, like:
// self?.myLabel.text = newValue
}
.addDisposableTo(disposeBag) // for resource management
b。更新をUILabelに直接バインドする
// add this ivar somewhere in ViewController
let disposeBag = DisposeBag()
// put this somewhere in viewDidLoad
SharingManager.sharedInstance.onUpdateLabel?
.distinctUntilChanged() // only if value has been changed since previous value
.observeOn(MainScheduler.instance) // do in main thread
.bindTo(myLabel.rx_text) // will setText: for that label when value changed
.addDisposableTo(disposeBag) // for resource management
また、ViewControllerでimport RxCocoa
を忘れないでください。
イベントをトリガーするには
SharingManager.sharedInstance.triggerLabelUpdate("whatever string here")
[〜#〜] here [〜#〜] プロジェクト例があります。 pod update
を実行し、ワークスペースファイルを実行するだけです。
アップルはこれらのプロパティ宣言タイプを提供します:-
1。計算されたプロパティ:-
格納されたプロパティに加えて、クラス、構造、および列挙は、実際に値を格納しない計算されたプロパティを定義できます。代わりに、他のプロパティと値を間接的に取得および設定するゲッターとオプションのセッターを提供します。
var otherBool:Bool = false
public var enable:Bool {
get{
print("i can do editional work when setter set value ")
return self.enable
}
set(newValue){
print("i can do editional work when setter set value ")
self.otherBool = newValue
}
}
2。読み取り専用の計算プロパティ:-
ゲッターはあるがセッターはない計算プロパティは、読み取り専用の計算プロパティと呼ばれます。読み取り専用の計算プロパティは常に値を返し、ドット構文を使用してアクセスできますが、別の値に設定することはできません。
var volume: Double {
return volume
}
3。プロパティオブザーバー:-
プロパティでこれらのオブザーバーのいずれかまたは両方を定義するオプションがあります。
willSetは、値が保存される直前に呼び出されます。
didSetは、新しい値が保存された直後に呼び出されます。
public var totalSteps: Int = 0 {
willSet(newTotalSteps) {
print("About to set totalSteps to \(newTotalSteps)")
}
didSet {
if totalSteps > oldValue {
print("Added \(totalSteps - oldValue) steps")
}
}
}
注:-詳細については、専門のリンクを参照してくださいhttps:// developer。 Apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html
var item = "initial value" {
didSet { //called when item changes
print("changed")
}
willSet {
print("about to change")
}
}
item = "p"