首页 > 解决方案 > 更新 NSHostingView 的关于单元重用的 SwiftUI 视图

问题描述

我有一个现有的 NSOutlineView,我想用一个接管整个 NSTableViewCell 的 SwiftUI 视图替换标准 UI 元素。当然,由于单元重用,我试图想出一种方法来更新 SwiftUI 视图,因为 outlineView 向下滚动......但我无法让它工作。SwiftUI 视图正确地渲染和显示它的元素,但在大多数情况下,它们显示的是错误的“人”的内容。这通常是标准 UIKit/AppKit 的简单单元重用问题,但在这种情况下,SwiftUI 视图由于某种原因没有更新。

举个例子,这是我为单元格制作的 SwiftUI 视图:

struct CJContactListCellView: View {
    
    @ObservedObject var person: Person
    
    var body: some View {
        
        VStack(alignment: .leading, spacing: 8.0) {
            CJContactProfileTop(person: person)        
        }
    }
}

Person是一个 NSManagedObject 子类,来自一个核心数据实体。这是我们滚动查看大纲视图时需要更新的内容。

为了创建和更新宿主视图,我创建了一个不同的类,它可以从 outlineView 单元类的 Objective-C 代码中调用:

@objc class CJContactsCellInterface: NSObject {
    @ObservedObject var person: Person
    var cellView: CJContactListCellView
    
    @objc func makeContactsCellView() -> NSView{
        self.cellView = CJContactListCellView(person: person)
        return NSHostingView(rootView: self.cellView)
    }
    
    @objc func updatePersonForTagsView(person: Person) {
        self.person = person
        self.cellView.person = person // I thought this would update the SwiftUI view, but it doesn't
    }
    
    @objc init(person: Person) {
        self.person = person
        self.cellView = CJContactListCellView(person: person)
        super.init()
    }
}

在 outlineView 的 viewForTableColumn:item: 委托方法中,我实例化了 nib:

result = [outlineView makeViewWithIdentifier:@"ContactsCellSwiftUICell" owner:self];
[result setupCellViewWithPerson: person];

NSTableCellView视图类中,我person在列表滚动时创建和更新对象:

- (void) setupCellViewWithPerson:(Person *)person {
    
    if (self.tagsViewInterface == nil) {
        
        self.tagsViewInterface = [[CJContactsTagsInterface alloc] initWithPerson: person];
        NSView *tagsView = [self.tagsViewInterface makeContactsCellView];
        
        tagsView.translatesAutoresizingMaskIntoConstraints = NO;
        [self addSubview: tagsView];
        
        [self addConstraint: [NSLayoutConstraint constraintWithItem: tagsView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.contactName  attribute:NSLayoutAttributeBottom multiplier:1.0 constant: 8.0]];
        
        [self addConstraint: [NSLayoutConstraint constraintWithItem: self attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:tagsView  attribute:NSLayoutAttributeBottom multiplier:1.0 constant: 8.0]];

        [self addConstraint: [NSLayoutConstraint constraintWithItem: self attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:tagsView attribute:NSLayoutAttributeLeading multiplier:1.0 constant: -8.0]];

        [self addConstraint: [NSLayoutConstraint constraintWithItem: self attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem: tagsView attribute:NSLayoutAttributeTrailing multiplier:1.0 constant: 8.0]];
    }
    
    self.contactName.stringValue = person.displayName; // just used for debugging
    [self.tagsViewInterface updatePersonForTagsViewWithPerson: person];
    
}

谁能指出我可能做错了什么?我希望由于我要替换PersonSwiftUI 视图中的对象,它会重新渲染整个视图;但我对组合和底层技术不太熟悉,所以可能有更好的方法来做到这一点。

标签: core-dataswiftuinstableviewappkitnsoutlineview

解决方案


推荐阅读