Swift, iboutlet and custom controls
Asked Answered
I

3

10

I may be doing something really stupid, but I don't seem to be able to use Interface Builder to connect IBOutlet variables to custom views, but only in Swift.

I've created a class called MyView, which extends from UIView. In my controller, I've got a MyView variable (declared as @IBOutlet var newView: MyView). I go into IB and drag a UIView onto the window and give it a class of MyView.

Whenever I've done similar in Objective C, I'm then able to click on the View Controller button at the top of the app window, select the variable and drag it down to the control to link the two together. When I try it in Swift, it refuses to recognise that the view is there.

If I change the class of the variable in the controller to UIView, it works fine. But not with my custom view.

Has anyone else got this problem? And is it a feature, or just my idiocy?

Code for Controller

import UIKit

class ViewController: UIViewController {

    @IBOutlet var newView:MyView

    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.
    }
}

Code for view

import UIKit

class MyView: UIView {

    init(frame: CGRect) {
        super.init(frame: frame)
        // Initialization code
    }

    /*
    // Only override drawRect: if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func drawRect(rect: CGRect)
    {
        // Drawing code
    }
    */

}
Inutile answered 8/6, 2014 at 9:17 Comment(1)
I'm experiencing this problem too, I think this is a bug and you should report it.Level
R
11

I've had a similar problem, and I think it's partially a caching issue and partially just an Xcode6/Swift issue. The first step I found was required was to make sure that the view controller .swift file would be loaded in the Assistant Editor when choosing "automatic".

With Xcode finding that both the files are linked I could sometimes control-drag from the view/button/etc. from the IB to the .swift file, but often had to drag from the empty circle in the gutter of the @IBOutlet var newView:MyView line to the view I wanted it to match up to.

If you can't get the file to load in the Assistant Editor then I found that doing the following would often work:

  1. Remove the custom class from the IB view
  2. Clean the project (cmd + K)
  3. Close/reopen Xcode
  4. Possibly clean again?
  5. Add the custom class back to the view
  6. Hope it works :)

If that seems to get you half way/nowhere add a comment and I'll see if it triggers anything else I did

Retroversion answered 8/6, 2014 at 9:35 Comment(2)
Thanks.None of that actually fixed the direct problem (dragging from an existing @IBOutlet to the custom view in the IB window), but did provide an alternate approach - dragging from the MyView in IB window into the assistant editor, which creates (and links) the relevant IBOutlet. This seems to achieve the same overall need.Inutile
Hooking from the empty circle in the gutter did the trick! thanks!Urus
S
3

In my case import UIKit was missing, after adding this line I could create an IBOutlet from Storyboard again.

Shawnshawna answered 17/6, 2015 at 13:12 Comment(0)
L
0

I've had a similar problem to the one described in this thread. Maybe you found a solution maybe not but anybody who encounters this in the future. I've found the key is to use the "required init" function as follows:

required init(coder aDecoder: NSCoder) {
    print("DrawerView: required init")
    super.init(coder: aDecoder)!
    screenSize = UIScreen.mainScreen().bounds
    screenWidth = screenSize.width
    screenHeight = screenSize.height
    self.userInteractionEnabled = true
    addCustomGestureRecognizer()
}

This is the complete class of my custom view:

import UIKit import Foundation

class DrawerView: UIView {

var screenSize: CGRect!
var screenWidth: CGFloat!
var screenHeight: CGFloat!

var drawerState: Int = 0

override init (frame : CGRect) {
    print("DrawerView: main init")
    super.init(frame : frame)
}

override func layoutSubviews() {
    print("DrawerView: layoutSubviews")
    super.layoutSubviews()
}

convenience init () {
    self.init(frame:CGRect.zero)
}

required init(coder aDecoder: NSCoder) {
    print("DrawerView: required init")
    super.init(coder: aDecoder)!
    screenSize = UIScreen.mainScreen().bounds
    screenWidth = screenSize.width
    screenHeight = screenSize.height
    self.userInteractionEnabled = true
    addCustomGestureRecognizer()
}

func addCustomGestureRecognizer (){
    print("DrawerView: addCustomGestureRecognizer")
    let swipeDown = UISwipeGestureRecognizer(target: self, action: #selector(self.handleDrawerSwipeGesture(_:)))
    swipeDown.direction = UISwipeGestureRecognizerDirection.Down
    self.addGestureRecognizer(swipeDown)
    let swipeUp = UISwipeGestureRecognizer(target: self, action: #selector(self.handleDrawerSwipeGesture(_:)))
    swipeUp.direction = UISwipeGestureRecognizerDirection.Up
    self.addGestureRecognizer(swipeUp)
    print("DrawerView self: \(self)")
}

func minimizeDrawer(){
    UIView.animateWithDuration(0.25, delay: 0.0, options: .CurveEaseOut, animations: {
        //            let height = self.bookButton.frame.size.height
        //            let newPosY = (self.screenHeight-64)*0.89
        //            print("newPosY: \(newPosY)")
        self.setY(self.screenHeight*0.86)
        }, completion: { finished in
            self.drawerState = 0
            for view in self.subviews {
                if let _ = view as? UIButton {
                    let currentButton = view as! UIButton
                    currentButton.highlighted = false
                } else if let _ = view as? UILabel {
                    let currentButton = view as! UILabel
                    if self.tag == 99 {
                        currentButton.text = "hisotry"
                    } else if self.tag == 999 {
                        currentButton.text = "results"
                    }
                }
            }
    })
}

func handleDrawerSwipeGesture(gesture: UIGestureRecognizer) {
    print("handleDrawerSwipeGesture: \(self.drawerState)")
    if let swipeGesture = gesture as? UISwipeGestureRecognizer {
        switch self.drawerState{
        case 0:
            if swipeGesture.direction == UISwipeGestureRecognizerDirection.Down {
                // nothing to be done, mini and swiping down
                print("mini: !")
            } else {
                // mini and swiping up, should go to underneath city box
                UIView.animateWithDuration(0.25, delay: 0.0, options: .CurveEaseOut, animations: {
                    let toYPos:CGFloat = 128 + 64 + 8
                    self.setY(toYPos)
                    }, completion: { finished in
                        self.drawerState = 1
                        for view in self.subviews {
                            if let _ = view as? UIButton {
                                let currentButton = view as! UIButton
                                currentButton.highlighted = true
                            } else if let _ = view as? UILabel {
                                let currentLabel = view as! UILabel
                                currentLabel.text = "close"
                            }
                        }

                })
            }
            break;
        case 1:
            if swipeGesture.direction == UISwipeGestureRecognizerDirection.Down {
                // open and swiping down
                self.minimizeDrawer()
            } else {
                // open and swiping up, nothing to be done
            }
            break;
        default:
            break;
        }
    }
}

}

Hope this helps...

Lalise answered 19/5, 2016 at 13:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.