custom datasource method is not calling in swift 2.0 - swift2

here is my BorderView and The task I'm trying to do is to hookup the custom object (Border) to the main storyboard.
import UIKit
protocol BorderViewDataSource: class{
func colorForBorderView(sender:BorderView) -> String? }
class BorderView: UIView {
#IBOutlet weak var topLeftImage: UIImageView!
#IBOutlet weak var topRightImage: UIImageView!
#IBOutlet weak var bottomLeftImage: UIImageView!
#IBOutlet weak var bottomRightImage: UIImageView!
var view: UIView!
weak var dataSource:BorderViewDataSource?
override init(frame: CGRect) {
super.init(frame: frame)
xtraSetup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
xtraSetup()
}
func xtraSetup() {
view = loadViewFromNib()
// use bounds not frame or it'll be offset
view.frame = bounds
// Make the view stretch with containing view
view.autoresizingMask = [UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleHeight]
// Adding custom subview on top of our view (over any custom drawing > see note below)
addSubview(view)
let borderColor = dataSource?.colorForBorderView(self) ?? "red"
applyColor(borderColor)
}
// this is an actual load from nib module
func loadViewFromNib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "BorderView", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return view
}
func applyColor(borderColor:String){
var imageName = "border-topleft-\(borderColor)"
topLeftImage.image = UIImage(named: imageName)
imageName = "border-topright-\(borderColor)"
print("Border color is \(borderColor), and Last image name is \(imageName)")
}
}
So when i open the app it will show the image of different color depending on what the value of the color is set in the ViewContorller.swift and here is my viewcontroller. swift code
class ViewController: UIViewController, BorderViewDataSource {
var borderType = 2
#IBOutlet weak var borderView: BorderView!{
didSet{
borderView.dataSource = self
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func colorForBorderView(sender: BorderView) -> String? {
var borderColor = "blue"
switch borderType {
case 1: borderColor = "blue"
case 2: borderColor = "purple"
case 3: borderColor = "red"
default: break
}
print("Border Type is \(borderType), and border color is \(borderColor)")
return borderColor
}
}
but colorForBorderView method is not calling when i running the app

It seems when the view is initialized, the dataSource property of that view is nil. And you only call that method during initialization of your view. You can apply the color after viewDidLoad() in your view controller

From the documentation:
When you assign a default value to a stored property, or set its
initial value within an initializer, the value of that property is set
directly, without calling any property observers.
That's the reason why the datasource is not set. Put the line borderView.dataSource = self into viewDidLoad()

Related

Border Doesn't Draw in NSView When inside NSTableCellView

I have three NSViews inside an NSTableCellView. Depending on the data for the row, I want to show a selected role with a border on the NSView like this:
The blue border NSView is a subclass that looks like this:
class RolePill: NSView{
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
layer?.cornerRadius = 9
layer?.borderWidth = 2
layer?.borderColor = NSColor.clear.cgColor
}
}
The role gets set initially when my table loads like this:
extension UsersVC: NSTableViewDelegate, NSTableViewDataSource{
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "UserCell"), owner: nil) as! UserCell
let user = users[row]
//Role
cell.setRole(role: user.role)
}
}
And my table cell, where the role gets set on load and on a button click, is set up like this:
class UserCell: NSTableCellView{
#IBOutlet weak var wrapOwner: RolePill!
#IBOutlet weak var wrapAdmin: RolePill!
#IBOutlet weak var wrapUser: RolePill!
#IBAction func clickOwner(_ sender: NSButton) {
setRole(role: "owner")
}
#IBAction func clickAdmin(_ sender: NSButton) {
setRole(role: "admin")
}
#IBAction func clickUser(_ sender: NSButton) {
setRole(role: "user")
}
func setRole(role: String){
let selectedColor = getAccentColor()
let offColor = Color(named: "BravoDark")!
let offTextColor = Color(named: "BFC0C2")
switch role{
case "owner":
wrapOwner.layer?.borderColor = selectedColor.cgColor
wrapAdmin.layer?.borderColor = offColor.cgColor
wrapUser.layer?.borderColor = offColor.cgColor
labelOwner.textColor = Color.white
labelAdmin.textColor = offTextColor
labelUser.textColor = offTextColor
case "admin":
wrapOwner.layer?.borderColor = offColor.cgColor
wrapAdmin.layer?.borderColor = selectedColor.cgColor
wrapUser.layer?.borderColor = offColor.cgColor
labelOwner.textColor = offTextColor
labelAdmin.textColor = Color.white
labelUser.textColor = offTextColor
default:
wrapOwner.layer?.borderColor = offColor.cgColor
wrapAdmin.layer?.borderColor = offColor.cgColor
wrapUser.layer?.borderColor = selectedColor.cgColor
labelOwner.textColor = offTextColor
labelAdmin.textColor = offTextColor
labelUser.textColor = Color.white
}
}
}
When the table loads initially, and anytime it refreshes (tableView.reloadData()) I lose my border and it looks like this:
As you can see, the textColor is set correctly to white. But for some reason, the border isn't set until I actually click on one of the IBAction buttons and manually trigger a change.
I suspect this is some kind of layer drawing bug where the RolePill class is redrawing every time my NSTableView reloads, but I don't know how to get it to accept the initial role state sent in tableView viewForRow.
Any idea what I'm doing wrong here? Thanks!
I was able to get this to work by setting all the NSView properties inside setRole() like this:
view.wantsLayer = true
view.layer?.cornerRadius = 11
view.layer?.borderWidth = 2
view.layer?.borderColor = getAccentColor().cgColor
label.textColor = Color.white
It seemed that the draw() method on my RolePill subclass was getting called frequently, so I couldn't set a border color in there since it doesn't know what the user's data state is.

How to access variable from one class in another? Swift Code

I am having an issue getting one simple variable from one class to another and it is beyond extremely frustrating :/...
Here is the deal I have two view controller classes named: ViewController.swift and ViewController2.swift
ViewController.swift is linked to a storyboard that has sort of an inventory bag that I have placed which is just an image. Then there is an #IBAction for when you click on the bag it opens up and the second storyboard pops into view. This is controlled by ViewController2.swift. All I am looking to do is simply pass the center of the bag image from ViewController to ViewController2 but I can't seem to get it to work any help would be greatly appreciated.
class ViewController: UIViewController {
#IBOutlet weak var InventoryBag: UIImageView!
var bagCenter:CGPoint = CGPoint(x: 0, y: 0)
override func viewDidLoad() {
super.viewDidLoad()
#IBAction func InventoryButtonTapped(sender: UIButton) {
self.InventoryBag.image = UIImage(named: "backpackimageopen")
bagCenter = self.InventoryBag.center
func transferViewControllerVariables() -> (CGPoint){
return bagCenter
}
When I print the bagCenter from this ViewController it works properly and gives me a correct value. So the bagCenter variable I would like to somehow pass over to ViewController2.swift.
Here is what I tried from ViewController2.swift but it never seems to work and always gives me a 0 rather than the actual value.
class ViewController2: UIViewController {
#IBOutlet weak var HideButton: UIButton!
#IBOutlet weak var InventoryCollection: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//Load the center of the inventory bag to this view controller to align the hide button.
var bagCenter = ViewController().transferViewControllerVariables()
}
But when I do this it always results in a 0 and I don't get the actual coords of the bag that are showing up in ViewController1.
Create a following variable in ViewController2
var previousViewController: ViewController!
Add following line of code in your ViewController Class
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?){
if segue.destinationViewController .isKindOfClass(ViewController2){
let vc2 = segue.destinationViewController as! ViewController2
vc2.previousViewController = self
}
}
Now in viewDidLoad method of ViewController2 you can access bagCenter like below:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
var bagCenter = previousViewController.transferViewControllerVariables()
}
Try this in view Controller
class ViewController: UIViewController {
#IBOutlet weak var InventoryBag: UIImageView!
var bagCenter:CGPoint = CGPoint(x: 0, y: 0)
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func InventoryButtonTapped(sender: AnyObject) {
self.InventoryBag.image = UIImage(named:"MAKEUP_SHARE.jpg")
bagCenter = self.InventoryBag.center
performSegueWithIdentifier("Go", sender: self)
}
// Give a segue identifier in storyboard
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "yoursegueidentifier" {
let dvc = segue.destinationViewController as? ViewController2
dvc!.bagCenter = bagCenter
}
}
}
and in view controller2
class ViewController2: UIViewController {
var bagCenter:CGPoint!
override func viewDidLoad() {
super.viewDidLoad()
print(bagCenter)
}
}

Reuse Code to set image

i´m developing an app that has a lot of view controllers and did set the back ground image with code, but i have to copy and paste that block of code in every view controller, how can i type it once and call it to reuse the code in every view controller..Thanks A lot.
var imageView: UIImageView!
let image = UIImage(named: "backGroundImage.png")!
override func loadView() {
super.loadView()
self.imageView = UIImageView(frame: CGRectZero)
self.imageView.contentMode = .ScaleAspectFill
self.imageView.image = image
self.view.addSubview(imageView)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.imageView.frame = self.view.bounds
}
What you can do is make a parent UIViewController class and have all of your view controllers inherit from that class. Somethig like this:
class MyParentViewController: UIViewController {
var imageView: UIImageView!
let image = UIImage()
override func viewDidLoad() {
super.viewDidLoad()
self.imageView = UIImageView(frame: CGRectZero)
self.imageView.contentMode = .ScaleAspectFill
self.imageView.image = image
self.view.addSubview(imageView)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.imageView.frame = self.view.bounds
}
}
And then your child view controllers that enherit from this class would look something like this:
class MyViewController: MyParentViewController {
overide func viewDidLoad() {
image = UIImage(named:"My image name")
super.viewDidLoad()
}
}
Now, here is really the way you should do it
However, having multiple view controllers that are all the same probably isnt a good idea. I would just keep only the parent view controller (rename it obviously) and just change the value of "image" in the segue that leads to the view to whatever image you want. This would eliminate the need to have a ton of view controllers, and will make it easier to add more images in the future if you want.
Here's how I would do it:
protocol ImageViewBackground {
var backgroundImageView: UIImageView? {get set}
mutating func setBackgroundImage(image: UIImage)
}
extension ImageViewBackground where Self: UIViewController {
mutating func setBackgroundImage(image: UIImage) {
let backgroundImageView = self.backgroundImageView ?? setupImageView()
backgroundImageView.image = image
}
mutating func setupImageView() -> UIImageView {
let imageView = UIImageView(frame: self.view.frame)
imageView.contentMode = .ScaleAspectFill
view.addSubview(imageView)
backgroundImageView = backgroundImageView
return imageView
}
}
Then just make any UIViewController adhere to the protocol like so:
class ViewController: UIViewController, ImageViewBackground {
var backgroundImageView: UIImageView?
}
Then you can call setBackgroundImage from anywhere in your VC without having to make a generic subclass just for the background image.

CustomView Does not show up in StatusBar

I am trying to make a SystemStatusBar popover for Mac. (Roughly, translating this Cocoa app to a Swift app). However, the view that I am using never shows up and the popup appears in the bottom left of the screen replicating the StatusBarItem.
This is what I expect (and that happens in the example from case of example from the link):
and this is what actually shows up (in my, Swift version of the application) instead of the NSPopover being shown in the StatusBar [Showing or Hiding the popup is controlled by the two buttons as shown in the previous figure. In this screenshot I have not added that window as it remains the same.]:
This is the AppDelegate:
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
var statusView : StatusView!
var popController: PopViewController!
#IBAction func showPop(sender: NSButton)
{
statusView.showPopup()
}
#IBAction func hidePop(sender: NSButton)
{
statusView.hidePopup()
}
func applicationDidFinishLaunching(aNotification: NSNotification)
{
var height = NSStatusBar.systemStatusBar().thickness
statusView = StatusView(frame: NSMakeRect(0, 0, CGFloat(height), CGFloat(height)))
}
}
The CustomView:
class StatusView : NSView, NSMenuDelegate
{
var imageView: NSImageView!
var statusItem: NSStatusItem!
var popover: NSPopover!
var popController: PopViewController!
required init? (coder: NSCoder)
{
super.init(coder: coder)
}
override init(frame frameRect: NSRect)
{
var height = NSStatusBar.systemStatusBar().thickness
imageView = NSImageView(frame: NSMakeRect(0, 0, CGFloat(height), CGFloat(height)))
statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(CGFloat(height))
super.init(frame: frameRect)
imageView.image = NSImage(named: "mf-image-black.png")
self.addSubview(imageView)
statusItem.view = self
popover = NSPopover()
popController = PopViewController(nibName: "PopViewController", bundle: nil)
popController.view = self
popover.contentViewController = popController
}
func showPopup()
{
if(!popover.shown)
{
popover.showRelativeToRect(self.frame, ofView: self, preferredEdge: NSMinYEdge)
}
}
func hidePopup()
{
if(popover.shown)
{
popover.close()
}
}
}
and the ViewController:
class PopViewController: NSViewController
{
#IBOutlet var statusView: StatusView!
override init?(nibName: String?, bundle: NSBundle?) {
super.init(nibName: nibName, bundle: bundle)
}
required init?(coder: NSCoder)
{
super.init(coder: coder)
}
}
I am not exactly sure what is that I am missing here. The StatusItem never seems to make use of the PopViewController nib.

Updates Labels in Swift when using popoverController

I have a question about swift,
I made a popover controller in a UIViewController,which display a list of books
and when the user click on one of the books, the label on the viewController should be updated with the name of the selected book.
But in my case when I select a name of a book, the label does not update
here is the code :
// View Controller
import UIKit
class ViewController: UIViewController,UIPopoverControllerDelegate {
var popoverController : UIPopoverController? = nil
#IBOutlet var bookName : UILabel
var BookNameString : String?{
didSet{
configureView()
}
}
func configureView() {
// Update the user interface for the detail item.
if let detail = self.BookNameString {
if let label = bookName {
label.text = detail
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func Click(sender : UIButton) {
var tableView:TableViewController = TableViewController(style: UITableViewStyle.Plain)
var popoverContent:UINavigationController = UINavigationController(rootViewController: tableView)
self.popoverController = UIPopoverController(contentViewController: popoverContent)
self.popoverController!.delegate = self
self.popoverController!.presentPopoverFromRect(sender.frame, inView: self.view, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
and here is the code of the TableViewController when a row is selected:
// TableViewController
override func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!){
var storyboard = UIStoryboard(name: "Main", bundle: nil)
var details = storyboard.instantiateViewControllerWithIdentifier("ViewController") as ViewController
var keyString = bookSectionKeys[indexPath.section]
var bookValues = book.booksLetters[keyString]!
var selectedBookString = bookValues[indexPath.row]
var selectedBookValues = book.bookDictionary[selectedBookString]!
details.BookNameString = selectedBookString
}
I was able to solve this problem a few weeks ago and I want to share the solution with you :)
I solve it using protocols.
OK Here what I did in details:
First I created a protocol in the view that I want it to display inside the popover and I named the protocol "DismissPopoverDelegate"
protocol DismissPopoverDelegate{
func didSelectBook(SelectedBook:String)
}
Then I declared a variable of type DismissPopoverDelegate and name it "delegate"
var delegate: DismissPopoverDelegate?
Then in the didSelectRowAtIndexMethod:
override func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!){
var keyString = bookSectionKeys[indexPath.section]
var bookValues = book.booksLetters[keyString]!
var selectedBookString = bookValues[indexPath.row]
delegate?.didSelectBook(selectedBookString)
}
After that inside the View that contains the popover (View Controller), I set the delegate of the view:
class ViewController: UIViewController, DismissPopOverDelegate, UIPopoverControllerDelegate{
Then to make the view confirm to the protocol DismissPopOverDelegate, I implement the method "didSelectBook" Inside the view:
func didSelectBook(SelectedBook:String){
popoverController!.dismissPopoverAnimated(true) // This is Optional
bookName.text = SelectedBook // Make the label text equal to the selected book From the table
}
Finally, I set the delegate to the tableView to View Controller
tableView.delegate = self
That's it :)
Here is the full code of the viewController that contains the popover
import UIKit
class ViewController: UIViewController, DismissPopOverDelegate, UIPopoverControllerDelegate{
#IBOutlet var booksbarButton : UIBarButtonItem
#IBOutlet var bookName : UILabel
var popoverController : UIPopoverController? = nil
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func showTableView(sender : UIBarButtonItem) {
var tableView:TableViewController = TableViewController(style: UITableViewStyle.Plain)
tableView.delegate = self
var popoverContent:UINavigationController = UINavigationController(rootViewController: tableView)
self.popoverController = UIPopoverController(contentViewController: popoverContent)
popoverController!.delegate = self
self.popoverController!.presentPopoverFromBarButtonItem(booksbarButton, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
}
func didSelectBook(SelectedBook:String){
popoverController!.dismissPopoverAnimated(true)
bookName.text = SelectedBook
}
}

Resources