我有一个表示底层数组的表视图。单元格有一个标签和一个滑块,它应该显示数组的percentage
属性的值。
我想使用键值观察来在百分比属性更改时更新标签。 (我知道KVO在这个例子中有点过分,但最终滑动一个滑块会影响其他单元格,包括滑块的位置,底层数组将从应用程序中的多个位置设置,随时都可以使用KVO。 )
我有一堆帮助from this answer,但我无法启动并更新标签。我在这里包含了我的所有代码。不知道我哪里出错了。
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, CustomCellDelegate {
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
for i in 0...4 {
items.append(Items(ID: i, percentage: 50))
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: myTableViewCell.ID) as? myTableViewCell {
cell.object = items[indexPath.row]
cell.mySlider.tag = indexPath.row
return cell
} else {
return UITableViewCell()
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
@IBAction func sliderValueChanged(_ sender: UISlider) {
items[sender.tag].percentage = Double(sender.value)
print("percentage at \(items[sender.tag].ID) is \(items[sender.tag].percentage)")
}
func didUpdateObject(for cell: UITableViewCell) {
if let indexPath = tableView.indexPath(for: cell) {
tableView.reloadRows(at: [indexPath], with: .automatic)
print("hello")
}
}
}
class myTableViewCell: UITableViewCell {
static let ID = "myCell"
weak var delegate: CustomCellDelegate?
private var token: NSKeyValueObservation?
var object: Items? {
willSet {
token?.invalidate()
}
didSet {
myLabel.text = "\(object?.percentage ?? 0)"
token = object?.observe(\.percentage) { [weak self] object, change in
if let cell = self {
cell.delegate?.didUpdateObject(for: cell)
}
}
}
}
override func awakeFromNib() {
super.awakeFromNib()
}
@IBOutlet weak var myLabel: UILabel!
@IBOutlet weak var mySlider: UISlider!
}
class Items: NSObject {
let ID: Int
@objc dynamic var percentage: Double
init(ID: Int, percentage: Double){
self.ID = ID
self.percentage = percentage
super.init()
}
}
var items: [Items] = []
protocol CustomCellDelegate: class {
func didUpdateObject(for cell: UITableViewCell)
}
答案 0 :(得分:2)
要在Swift 4中执行KVO,您必须将该属性声明为dynamic
并在该对象上调用observe(_:options:changeHandler:)
,从而保存生成的NSKeyValueObservation
令牌。当该令牌超出范围(或被另一个令牌替换)时,将自动删除原始观察者。
在您的情况下,您让观察者调用委托,然后重新加载单元格。但是你似乎永远不会设置delegate
属性,所以我怀疑该方法没有被调用。
但这一切似乎有点脆弱。我倾向于直接在观察者的changeHandler
中更新标签。我还认为你可以更直接地更新单元格(我将“值已更改”的IBAction放在单元格中,而不是表格视图中),并消除了tag
使用class CustomObject: NSObject {
let name: String
@objc dynamic var value: Float // this is the property that the custom cell will observe
init(name: String, value: Float) {
self.name = name
self.value = value
super.init()
}
}
来识别哪个非常笨拙模型数组中的行更新了滑块(如果插入或删除行,则可能会出现问题)。
所以考虑一下这个对象:
objects
然后,您可以拥有一个表视图控制器,该控制器使用此模型类型的实例填充class ViewController: UITableViewController {
var objects: [CustomObject]!
override func viewDidLoad() {
super.viewDidLoad()
// self sizing cells
tableView.estimatedRowHeight = 60
tableView.rowHeight = UITableViewAutomaticDimension
// populate model with random data
let formatter = NumberFormatter()
formatter.numberStyle = .spellOut
objects = (0 ..< 1000).map {
CustomObject(name: formatter.string(for: $0)!, value: 0.5)
}
}
}
// MARK: - UITableViewDataSource
extension ViewController {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objects?.count ?? 0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.object = objects[indexPath.row]
return cell
}
}
数组。这里的细节与观察结果基本无关(我们将在下面介绍),但我将其包括在内只是为了提供一个完整的例子:
dynamic
完成后,您现在可以拥有单元格的基类(a)如果滑块更改,则更新模型对象; (b)观察对value
属性的更改,在此示例中,在模型对象中观察到class CustomCell: UITableViewCell {
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var valueLabel: UILabel!
@IBOutlet weak var valueSlider: UISlider!
static private let formatter: NumberFormatter = {
let _formatter = NumberFormatter()
_formatter.maximumFractionDigits = 2
_formatter.minimumFractionDigits = 2
_formatter.minimumIntegerDigits = 1
return _formatter
}()
private var token: NSKeyValueObservation?
weak var object: CustomObject? {
didSet {
let value = object?.value ?? 0
nameLabel.text = object?.name
valueLabel.text = CustomCell.formatter.string(for: value)
valueSlider.value = value
token = object?.observe(\.value) { [weak self] object, change in
self?.valueLabel.text = CustomCell.formatter.string(for: object.value)
}
}
}
@IBAction func didChangeSlider(_ slider: UISlider) {
object?.value = slider.value
}
}
更改时更新标签:
#define mykey 12345
#define perms 0666
struct pdata{
int ppid;
char ptype;
char *pname;
unsigned long pgenome;
};
int main(int argc, char **argv){
int shmid;
char *args[] = {"test2", NULL};
struct pdata *ap;
struct pdata p0={12, 'A', "PIPPO", 100};
shmid = shmget(mykey, sizeof(struct pdata) * 1, perms | IPC_CREAT | IPC_EXCL);
ap = (struct pdata*) shmat(shmid, NULL, 0);
ap[0] = p0;
printf("%s\n", ap[0].pname);
if(execve("test2", args, NULL) == -1){
printf("Errore execve\n");
}
shmdt(ap);
shmctl(shmid, IPC_RMID, 0);
return 0;
}
产量:
有关详细信息,请参阅Using Swift with Cocoa and Objective-C: Adopting Cocoa Patterns的“键值观察”部分。
答案 1 :(得分:0)
嗨@sean问题在UITableview单元类中你已经制作了diSet方法,所以你不需要为cell.lable和slider传递值只是尝试下面的代码
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: myTableViewCell.ID) as? myTableViewCell {
//pass the object to which you wanna add observer to cell
cell.object = items[indexPath.row]
return cell
} else {
return UITableViewCell()
}
}