أعتقد أنني في حيرة من أمري حول كيفية عمل Disposable
s. لدي فئة فرعية UITableViewCell
مع خاصية viewModel
. في didSet
من viewModel
أستدعي الوظيفة التالية:
private func setupBindings() {
if let friendViewModel = friendViewModel {
disposableBindings += friendViewModel.statusLabel.producer.startWithNext({ status in
self.statusLabel.text = status
})
}
}
يحتوي friendViewModel
على MutableProperty
يُسمى statusLabel
ويبدو كما يلي:
let statusLabel = MutableProperty<String>("")
هذه الخاصية disposableBindings
هي ملكية CompositeDisposable
، والتي أنا "أتصرف بها" في طريقة prepareForReuse()
متجاوزة ، مثل:
override func prepareForReuse() {
disposableBindings.dispose()
}
المشكلة هي أن statusLabel
لا يتم تحديثه في أي وقت بعد إرسال الإشارة الأولى. لقد صححت هذا الخطأ ولم يتم استدعاء prepareForReuse()
. عندما أضيف logEvents()
مثل ...producer.logEvents().startWithNext({...
أحصل على مخرجات في وحدة التحكم مثل:
[] Started fileName: /NotImportant/ButAllTheSame, functionName: setupBindings(), lineNumber: 60
[] Next Tap to invite... fileName: /NotImportant/ButAllTheSame, functionName: setupBindings(), lineNumber: 60
[] Interrupted fileName: /NotImportant/ButAllTheSame, functionName: setupBindings(), lineNumber: 60
[] Terminated fileName: /NotImportant/ButAllTheSame, functionName: setupBindings(), lineNumber: 60
[] Disposed fileName: /NotImportant/ButAllTheSame, functionName: setupBindings(), lineNumber: 60
أنا في حيرة من أمري لماذا يتم إرسال حدث Interrupted
على المنتج؟ هذا MutableProperty
، لذا لست متأكدًا من سبب إرسال المقاطعة. يجب أن أضيف ذلك من خلال التجربة والخطأ ، لقد وجدت أن مجرد تجاهل المتاح يحل المشكلة:
friendViewModel.statusLabel.producer.logEvents().startWithNext({ status in
self.statusLabel.text = status
})
ومع ذلك ، كما هو متوقع ، أنا متأكد من أن هذا يؤدي إلى حدوث مشكلات أخرى حيث لا تحتوي الخلايا المعاد استخدامها على إشارات من الاستدعاءات السابقة setupBindings()
التخلص منها ويقومون بتغيير النص statusLabel
مع القيم من منتج العرض الخاطئ statusLabel
MutableProperty
المنتج.
ما الذي افتقده هنا؟
يرسل المنتج حدثًا interrupted
عندما يتم مقاطعته يدويًا (عبر المتاح).
إذا تخلصت من المنتجين المبتدئين (المعروفين أيضًا باسم الإشارة المنتجة) ، فستحتاج إلى إعادة التأسيس بعد ذلك.
علاوة على ذلك ، لا يمكن إعادة استخدام Disposable
التخلص منه ، وفي حالتك يجب استبدال CompositeDisposable
بمثيل جديد عند إعادة الاستخدام.
ومع ذلك ، يمكنك بدلاً من ذلك التفكير في تخزين نموذج العرض في MutableProperty
واستخدام flatMap
لتحقيق نفس الهدف.
// Assume viewModel is optional.
viewModel.producer.ignoreNil()
.flatMap(.latest) { $0.statusLabel.producer }
بهذه الطريقة لن تضطر إلى إدارة المستهلكات بنفسك ، بينما تتم معالجة الروابط تلقائيًا عند تحديث خاصية نموذج العرض. تحتاج فقط إلى ربط هؤلاء المنتجين المسطحين مرة واحدة بوجهتهم ، على سبيل المثال في awakeFromNib
.
ملاحظة: يمكنك تسوية الخصائص مباشرة في Swift 3.0.
andersio شكرا لك هذا رائع!
أيضًا ، لمعلوماتك فقط ، فقد ساعدك تفسيرك أيضًا. عندما قمت بتغيير الرمز ليكون بدلاً من ذلك:
private var disposableBindings = CompositeDisposable()
private func setupBindings() {
disposableBindings += friendViewModel.statusLabel.producer.startWithNext({ status in
self.statusLabel.text = status
})
}
}
override func prepareForReuse() {
disposableBindings.dispose()
disposableBindings = CompositeDisposable()
}
تستمر الإشارة حتى إعادة استخدام الخلية. أعتقد أن المشكلة كانت مني في إعادة استخدام CompositeDisposable. كنت أعامله مثل NSCache أو شيء من هذا القبيل.
شكرا لك مرة أخرى!
التعليق الأكثر فائدة
andersio شكرا لك هذا رائع!
أيضًا ، لمعلوماتك فقط ، فقد ساعدك تفسيرك أيضًا. عندما قمت بتغيير الرمز ليكون بدلاً من ذلك:
تستمر الإشارة حتى إعادة استخدام الخلية. أعتقد أن المشكلة كانت مني في إعادة استخدام CompositeDisposable. كنت أعامله مثل NSCache أو شيء من هذا القبيل.
شكرا لك مرة أخرى!