Как отразить новый раздел для UICollectionView в RxDataSource? - PullRequest
0 голосов
/ 29 января 2019

Я создаю приложение для iOS с RxSwift и RxDataSource, используя архитектуру VIPER.Я хочу изменить содержимое UICollectionView при изменении значения презентатора (поскольку пользователь набрал несколько букв в строке поиска, collectionView должен отображать профиль всех пользователей, который начинается с букв), но он не работает какЯ хотел это.

При попытке использования функции debug() значение presenter.section в ViewController (которое содержит содержимое CollectionView) изменяется после того, как я набрал некоторые буквы в строке поиска.Тем не менее, collectionView не отражает изменения.Вот основные части кода.

код ViewController

override func viewDidLoad() {

    super.viewDidLoad()
    self.view.backgroundColor = .white

    self.presenter.section
        .drive(self.searchedFriendsCollectionView.rx.items(dataSource: self.dataSource))
        .disposed(by: self.disposeBag)

    self.searchedFriendsCollectoinView.rx
        .setDelegate(self)
        .disposed(by: self.disposeBag)
}

код Presenter

init(view: SearchFriendsViewInterface, interactor: 
SearchFriendsInteractorInterface, wireframe: 
SearchFriendsWireframeInterface) {

    self.view = view
    self.interactor = interactor
    self.wireframe = wireframe

    let allUsers = self.interactor.allUsers().asObservable()

    self.view.searchText
        .debounce(0.5)
        .filterNil()
        .distinctUntilChanged()
        .filterEmpty()
        .asObservable()
        .flatMap { text -> Observable<[SearchFriendsSection]> in
            // get all users starting with "text"
            allUsers.mapSections(query: text)
        }
        .bind(to: self.section)
        .disposed(by: self.disposeBag)
} 

extension Observable where E == [User] {

fileprivate func mapSections(query: String) -> Observable<[SearchFriendsSection]> {

    return self.map {
            $0.filter { $0.userDisplayName.hasPrefix(query) || $0.username.hasPrefix(query) }
        }
        .map { users -> [SearchFriendsSection] in

            let items = users.map { user in
                SearchFriendsItem(icon: user.profileImageURL, displayName: user.userDisplayName)
            }
            return [SearchFriendsSection(items: items)]
        }
    }
}

Как я определил dataSource

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {

    self.searchedFriendsCollectoinView = UICollectionView(frame: .init(), collectionViewLayout: self.searchedFriendsCollectionViewFlowLayout)
    let dataSource = RxCollectionViewSectionedReloadDataSource<SearchFriendsSection> (configureCell: {(_, collectionView, indexPath, item) -> UICollectionViewCell in
        collectionView.register(SearchFriendsCell.self, forCellWithReuseIdentifier: "SearchFriendsCell")
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SearchFriendsCell", for: indexPath) as! SearchFriendsCell
        cell.item = item
        return cell
    })
    self.dataSource = dataSource
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
  • В ViewController есть экземпляр Presenter, а в Presenter - section.section содержит список пользователей, чьи имена начинаются с определенных букв.

Не могли бы вы мне помочь?Если я оставил что-то неясным, пожалуйста, дайте мне знать в комментарии.

Обновление: вывод debug()

2019-02-01 10:22:27.610: values -> subscribed
2019-02-01 10:22:27.611: values -> Event next([])
--after typed in some letters in the searchBar--
2019-02-01 10:22:41.494: values -> Event 
next([AppScreen.SearchFriendsSection(items: 
[AppScreen.SearchFriendsItem(....), 
AppScreen.SearchFriendsItem(....), 
AppScreen.SearchFriendsItem(....)])])

Ответы [ 3 ]

0 голосов
/ 01 февраля 2019

Я нашел вашу проблему.Вы никогда не добавляли представление коллекции в свой основной вид.Если представление коллекции не имеет суперпредставления или оно имеет нулевой размер, загрузка его не беспокоит.

Поместите эти две строки в ваш viewDidLoad:

searchedFriendsCollectionView.frame = view.bounds
view.addSubview(searchedFriendsCollectionView)

Покавы находитесь в этом, вы должны переместить эту строку из вашего закрытия конфигурации в viewDidLoad:

searchedFriendsCollectionView.register(SearchFriendsCell.self, forCellWithReuseIdentifier: "SearchFriendsCell")

Нет причин звонить, чтобы каждый раз, когда система запрашивает ячейку.

0 голосов
/ 01 февраля 2019

Хорошо, наконец-то я решил это, и это не было напрямую связано с Rxswift.Я использовал FlexLayout для компоновки всего, и в CollectionViewCell я не поместил код ниже.

override func layoutSubviews() {

    super.layoutSubviews()
    self.contentView.flex.layout()
}

Не было никакой причины, по которой представление обновляется без этого кода, потому что FlexLayout не выполняет макет безэтот код

0 голосов
/ 29 января 2019

Просто интересно, как вы определяете self.interactor.allUsers() и allUsers.mapSections(query: text)

Вы звонили onNext(), чтобы уведомить наблюдателя о новом элементе в последовательности.после того, как вы отобразили разделы или получили всех пользователей?

Если вы действительно хотите использовать flatMap.Я думаю, что вы должны использовать flatMapLatest вместо

Ссылка: Карта RxSwift и разница flatMap

Обновлено: в этом случае вам нужно создать новую наблюдаемую в mapSections, котораявсегда генерировать [SearchFriendsSection] и отправлять его наблюдателю

 return Observable.create { observer in
        let filteredSections = ...
        observer.on(.next(filteredSections))
        observer.on(.completed)
        return Disposables.create()
    }
...