Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UITableViewCell/UICollectionViewCell input example #26

Closed
ipaboy opened this issue Oct 2, 2017 · 4 comments
Closed

UITableViewCell/UICollectionViewCell input example #26

ipaboy opened this issue Oct 2, 2017 · 4 comments

Comments

@ipaboy
Copy link

ipaboy commented Oct 2, 2017

Hi Guys, I'm very exited with this architecture and want to thank you. While working with it I've got some questions. Could you please provide an example for the following case: I have a cell with a textfield placed on it. How should I create an Input for controller's ViewModel in this case to make it work properly with cells reusability?

Thanks.

@nmdias
Copy link

nmdias commented Oct 20, 2017

Hi @bryzinski,

Have a look at the AllPosts scene in this repository. It does what you're describing. Ping me if you need help in understanding anything in particular.

Cheers

@ipaboy
Copy link
Author

ipaboy commented Oct 31, 2017

Hi @nmdias thank you for your feedback. But unfortunately PostTableViewCell doesn't contain any UITextFields. To clarify I'm interested in a table view based form screen and looking for an elegant solution to pass rx streams of textfields (which are placed on cells) through view models's -transform method.

Probably the easiest way is to add Variable's to view model (like username, password) and bind them directly after cells are dequeued. But I love this transform function and still looking for the solution :)

@nmdias
Copy link

nmdias commented Nov 1, 2017

Hey @bryzinski,

Ah! A UITextfield! Yeah, that's different. I use a Base class. Consider the following:

class BaseTableViewCell<ViewModelType>: UITableViewCell, Reusable {
    
    private var disposeBag: DisposeBag?
    
    var viewModel: ViewModelType? {
        didSet {
            guard let viewModel = viewModel else {
                return
            }
            let disposeBag = DisposeBag()
            self.configure(viewModel, disposedBy: disposeBag)
            self.disposeBag = disposeBag
        }
    }
    
    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        configureDefaults()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    public override func prepareForReuse() {
        super.prepareForReuse()
        self.disposeBag = nil
        self.viewModel = nil
    }
    
    func configureDefaults() {
        fatalError("Always override \(#function) to provide default view configurations.")
    }
    
    func configure(_ viewModel: ViewModelType, disposedBy disposeBag: DisposeBag) {
        fatalError("Always override \(#function) to provide view model configurations.")
    }
    
}

Now, with your own subclass, you could do this, maybe?

final class SomeTableViewCell: BaseTableViewCell<SomeTableViewCellViewModel> {
    
    let textfield: UITextField = {
        let textfield = UITextField()
        textfield.translatesAutoresizingMaskIntoConstraints = false
        // Do your thing
        return textfield
    }()
    
    override func configureDefaults() {
        // Do your thing
    }
    
    override func configure(_ viewModel: SomeTableViewCellViewModel, disposedBy disposeBag: DisposeBag) {
        // I suspect there might be a cleaner way to `drive` the subject...
        textfield.rx.text.asDriver().drive(onNext: { (string) in
            viewModel.text.on(.next(string))
        }).disposed(by: disposeBag)
    }
    
}

The cell has this corresponding ViewModelType:

struct SomeTableViewCellViewModel {
    let text = PublishSubject<String?>()
}

Now, when you instantiate your Cell's View Model, you can subscribe to it's text: PublishSubject<String?>

Something like:

// The Cell's View Model
viewModel.text.subscribe(onNext: { (string) in
    print(string)
}).disposed(by: disposeBag)

Then assign the Cell's viewModel

let cell = tableView.reusableCell() as SomeTableViewCell
cell.viewModel = viewModel
return cell

Does this help? Cheers

@ipaboy
Copy link
Author

ipaboy commented Jan 10, 2018

@nmdias thank you! It looks what I expected for.

@ipaboy ipaboy closed this as completed Jan 10, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants