NSTableview with RXSwift and RxCocoa for OSX - macos

How do I populate the NSTableview with an array using reactive framework?
In iOS for UITableview:
self.viewModel.arrayElements.asObservable()
.observeOn(MainScheduler.instance)
.bind(to: detailsTableView.rx.items(cellIdentifier: "comment", cellType: UITableViewCell.self)){
(row,element,cell) in
cell.addSubview(cellView)
}.addDisposableTo(disposeBag)
how can i achieve the same for NSTableView

I ran into a similar need, and solved it with a BehaviorRelay (using RxSwift 5).
The BehaviorRelay acts as a mediator so it's possible to use regular NSTableViewDataSource and NSTableViewDelegate protocols
The important part is the self.detailsTableView.reloadData() statement which tells the tableview to reload the data, it is not triggered automatically.
Something like this:
var disposeBag = DisposeBag()
var tableDataRelay = BehaviorRelay(value: [Element]())
func viewDidLoad() {
viewModel.arrayElements.asObservable()
.observeOn(MainScheduler.instance)
.bind(to: tableDataRelay).disposed(by: disposeBag)
tableDataRelay
.observeOn(MainScheduler.instance)
.subscribe({ [weak self] evt in
self.detailsTableView.reloadData()
}).disposed(by: disposeBag)
}
func numberOfRows(in tableView: NSTableView) -> Int {
return tableDataRelay.value.count
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
let element = tableDataRelay.value[row]
let cellView = tableView.makeView(withIdentifier: tableColumn!.identifier, owner: nil) as? NSTableCellView
cellView?.textField?.stringValue = element.comment
return cellView
}

Try the below, you should use drivers not observables
read this https://github.com/ReactiveX/RxSwift/blob/master/Documentation/Traits.md
import RxSwift
import RxCocoa
let data = Variable<[String]>([])
let bag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
data.asDriver.drive( tableView.rx.items(cellIdentifier: "idenifier")){(row:Int, comment:String, cell:UITableViewCell) in
cell.title = report
}.disposed(by:bag)
}

Related

Nstableview with custom tablecellview not displaying any data

Tableview is loading but not displaying any outlet from custom cell
class ViewController: NSViewController,NSTableViewDataSource,NSTableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
//let color : CGColorRef = CGColorCreateGenericRGB(1.0, 0, 0, 1.0)
self.view.layer?.backgroundColor = NSColor.whiteColor().CGColor
// Do any additional setup after loading the view.
}
override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
func tableView(tableView: NSTableView, viewForTableColumn tableColumn: NSTableColumn?, row: Int) -> NSView? {
let cell = tableView.makeViewWithIdentifier("AppointmentCell", owner: self) as! AppointmentCell!
if tableColumn!.identifier == "Column" {
return cell
}
return cell
}
func numberOfRowsInTableView(tableView: NSTableView) -> Int {
return 5
}
func tableView(tableView: NSTableView, heightOfRow row: Int) -> CGFloat
{
return 100
}
}
class AppointmentCell: NSTableCellView {
#IBOutlet weak var Start: NSButton!
#IBOutlet weak var Increment: NSButton!
#IBOutlet weak var decrement: NSButton!
#IBOutlet weak var addNotes: NSButton!
override func drawRect(dirtyRect: NSRect) {
super.drawRect(dirtyRect)
// Drawing code here.
}
}
You need check if cell is existed.
After dequeue a cell view from tableview, you should set you content in cell view.
It usually occur in
func tableView(tableView: NSTableView, viewForTableColumn tableColumn: NSTableColumn?, row: Int) -> NSView?

Populating NSTableView from array in Swift (without XCode)

I'm trying to develop for OS X without the use of XCode in Swift. I'm running into extreme headaches trying to populate NSTableView from any kind of data source. Here is my code:
import Cocoa
class StupidDataSource: NSObject, NSTableViewDataSource, NSTableViewDelegate {
var lib:[NSDictionary] = [["a": "1", "b": "2"],
["a": "3", "b": "4"]]
func numberOfRowsInTableView(tableView: NSTableView) -> Int {
return lib.count
}
func tableView(tableView: NSTableView,
objectValueForTableColumn tableColumn: NSTableColumn?,
row: Int) -> AnyObject? {
let result = lib[row].objectForKey(tableColumn!.identifier)
return result
}
}
func make_table(window: NSWindow,
_ size:(x:Int, y:Int, width:Int, ht:Int),
_ title:String,
_ data:StupidDataSource
)-> NSTableView {
let tableContainer = NSScrollView(frame:NSMakeRect(0, 0, 400, 400))
let tableView = NSTableView(frame: NSMakeRect(0, 0, 400, 400))
tableView.setDataSource(data)
tableView.reloadData()
tableContainer.documentView = tableView
tableContainer.hasVerticalScroller = true
window.contentView!.addSubview(tableContainer)
return tableView
}
class AppDelegate: NSObject, NSApplicationDelegate {
let window = NSWindow()
func applicationDidFinishLaunching(aNotification: NSNotification)
{
set_window_args(window, 400, 400, "Ass")
let dumb_dict = StupidDataSource()
let tableytable = make_table(window, (100, 100, 0 ,0), "poop", dumb_dict)
window.makeKeyAndOrderFront(window)
window.level = 1
}
}
let app = NSApplication.sharedApplication()
app.setActivationPolicy(.Regular)
let controller = AppDelegate()
app.delegate = controller
app.run()
This can be run at the command line with "swift file.swift". I have implemented the methods required for NSTableViewDataSource, and initialized everything correctly according to Apple's documentation, yet nothing shows up in the table. What is missing?
I'm no expert but it looks to me as though your tableView function is just returning the contents of the relevant row from the dictionary.
I personally return a cell as an NSView? like:-
func tableView(tableView: NSTableView, viewForTableColumn tableColumn: NSTableColumn?, row: Int) -> NSView?
{
if let cell = myViewBasedTableView.makeViewWithIdentifier(tableColumn!.identifier, owner: nil) as? NSTableCellView
{
cell.textField!.stringValue = "Hello";
// Instead of "Hello". Put the contents of one element from your
// dict in here. This func is called automatically for every cell
// in the grid.
return cell;
}
return myEmptyDefaultCell;
}
Having said that maybe your example is correct for Cell Based tableView. I never used one of them so don't know. I always use viewBased table view. I often put little images/icons in the cells as well as text using code like:
cell.textField!.stringValue = "Hello";
cell.imageView!.image = smileyFace;
return cell;

How to transfer data from table cell to a new view controller using prepare for segue method?

How to use prepare for segue to transfer the images (tweetImg) and date (dateLbl) from tablecell (mainCell) to the Newviewcontroller when I select the cell? in my case I am using parse.com as my backend to retrieve the images and dates data. I am new to programming would appreciate some help, thank you.
mainVC
import UIKit
class mainVC: UIViewController, UITableViewDataSource, UITableViewDelegate, {
#IBOutlet weak var resultsTable: UITableView!
var resultsStartdateArray = [String]()
var resultsTweetImageFiles = [PFFile?]()
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return resultsTweetImageFiles.count
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 350
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:mainCell = tableView.dequeueReusableCellWithIdentifier("Cell") as! mainCell
cell.dateLbl.text = self.resultsStartdateArray[indexPath.row]
resultsTweetImageFiles[indexPath.row]?.getDataInBackgroundWithBlock({
(imageData:NSData?, error:NSError?) -> Void in
if error == nil {
let image = UIImage(data: imageData!)
cell.tweetImg.image = image
}
})
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("SendDataSegue", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if (segue.identifier == "SendDataSegue")
{
let destination: NewViewController = segue.destinationViewController as! NewViewController
// I believe the missing code should be here
}
}
}
mainCell
import UIKit
class mainCell: UITableViewCell {
#IBOutlet weak var tweetImg: UIImageView!
#IBOutlet weak var dateLbl: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
}
NewViewController
import UIKit
class NewViewController: UIViewController {
#IBOutlet weak var dateLbl: UILabel!
#IBOutlet weak var tweetImg: UIImageView!
var titleString: String!
override func viewDidLoad()
{
super.viewDidLoad()
self.dateLbl.text = self.titleString
}
Bellow i have mentioned a sample template code. organize your code according to bellow mentioned code. important part is select a cell in the prepareForSegue instead of in didSelectRowAtIndexPath. Which is let IndexPath = self.tableView.indexPathForSelectedRow()!
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
//Index path is the selected cell
let IndexPath = self.tableView.indexPathForSelectedRow()!
//Here you can assign your tweetImg and dateLbl
let newViewController = segue.destinationViewController as! NewViewController
newViewController.dateLbl.text = //your date label value
//here assign your image to destination view controller property
}
Delete the method didSelectRowAtIndexPath and connect the segue to the table view cell rather than the view controller.
When a cell is selected it's passed as the sender parameter in the prepareForSegue method.
A side note : Don't perform background tasks in the view – the cellForRowAtIndexPath method – , do it in the model – the items in the data source array – and then call reloadData()

Xcode 7 - Cell content not displayed into an empty label

I'm trying to display a cell content into an empty UILabel, but after I upgraded to Xcode 7, the content didn't show up. I was following the same mechanism and it worked on Xcode 6, but since I'm new to Swift I may have something wrong in the code.
TableViewController:
import UIKit
class TableViewController: UITableViewController {
struct dataModel {
var name:String
var val:Double
}
let foods = [dataModel(name: "name1", val: 3.3),
dataModel(name: "name2", val: 5.5)]
#IBOutlet var table: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return foods.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
// Configure the cell...
let foodCell = foods[indexPath.row]
cell.textLabel?.text = foodCell.name
return cell
}
var valueToPass:String!
var valueInt:Int!
override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
let indexPath = tableView.indexPathForSelectedRow;
let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as UITableViewCell!;
valueToPass = currentCell.textLabel!.text
performSegueWithIdentifier("showCalc", sender: self)
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "showCalc") {
let viewController = segue.destinationViewController as! calcViewController
viewController.passedValue = valueToPass
}
}
}
ViewController where I want to display the tapped cell into an empty label:
import UIKit
class calcViewController: UIViewController {
#IBOutlet var text: UILabel!
#IBOutlet var empty1: UILabel!
var passedValue:String!
override func viewWillAppear(animated: Bool) {
empty1.text = passedValue
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
As a result, there is no error, but there is nothing displayed inside the empty label.
The other thing I want to achieve is to display the Int value into another label and then do some calculations, but this would be another question. Thanks in advance!
There are several issues in this code. First you are obviously missing some closing braces. But I assume this is a copy-paste error.
Why do you use didDeselectRowAtIndexPath? Don't you have a segue from the table view cell to the next controller? Then you should get the text label in prepareForSegue by using tableView.indexPathForSelectedRow.
If you like to keep it this way you should use didSelect... in stead of didDeselect....
You should take the value you want to pass to the next view controller direct from the data and not from the cell. You have the data you present in the table in the foods array.
Class names should always start with a capital letter. ALWAYS!
Having the data model within the controller is poor design. You should have the struct separated in its own file. In this case you could even hand the complete data object to the next view controller.

Load data to UITableView

I have data saved like this:
var mineSpillere = ["erik", "tom", "phil"]
How can i add that data to a UITableView by pressing a UIButton like this?:
#IBAction func backButtonAction(sender: AnyObject) {
// Press this button here to add the "mineSpillere" data to myTableView
}
Set the data source of the table view inside the IBAction. so like this:
#IBAction func backButtonAction(sender: AnyObject) {
myTableView.dataSource = self
// Loading from NSUserDefaults:
// Please name it something better than array I couldn't come up with any names.
if let array = NSUserDefaults.standardUserDefaults().arrayForKey("key") as? [String]
{
// The key exists in user defaults
}
else
{
// The key doesn't exist in the user defaults, do some error handling here.
}
}
And then implement the data source:
extension MyVC : UITableViewDataSource
{
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return mineSpillere.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = UITableViewCell(style: .Default, reuseIdentifier: "cell")
cell.textLabel!.text = mineSpillere[indexPath.row]
return cell
}
}

Resources