Swift - Iboutletcollection Equivalent

Swift - IBOutletCollection equivalent

EDIT

This was fixed in a later Beta release of Swift - there's now in
IBCollection option in the interface builder.


For early Beta releases of Swift:

I came across the same problem: in the release notes of Beta 2 you find the following statement:

Interface Builder does not support declaring outlet collections in Swift classes

I solved this the following way (easy to customize):

class CardGameViewController: UIViewController {
@lazy var cardButtons : UIButton[] = {
var tempBtn: UIButton[] = []
for v:AnyObject in self.view.subviews {
if v is UIButton {
tempBtn.append(v as UIButton)
}
}
return tempBtn
}()
...

Basically, it loops through all the subviews and checks if one is a UIButton. In that case it gets added to a temporary array. This temporary array is then used to lazy instantiate the cardButtons array. For all details, check: Matchismo: Objective-C to Swift

IBOutletCollection set ordering in Interface Builder

EDIT: Several commenters have claimed that more recent versions of Xcode return IBOutletCollections in the order the connections are made. Others have claimed that this approach didn't work for them in storyboards. I haven't tested this myself, but if you're willing to rely on undocumented behavior, then you may find that the explicit sorting I've proposed below is no longer necessary.


Unfortunately there doesn't seem to be any way to control the order of an IBOutletCollection in IB, so you'll need to sort the array after it's been loaded based on some property of the views. You could sort the views based on their tag property, but manually setting tags in IB can be rather tedious.

Fortunately we tend to lay out our views in the order we want to access them, so it's often sufficient to sort the array based on x or y position like this:

- (void)viewDidLoad
{
[super viewDidLoad];

// Order the labels based on their y position
self.labelsArray = [self.labelsArray sortedArrayUsingComparator:^NSComparisonResult(UILabel *label1, UILabel *label2) {
CGFloat label1Top = CGRectGetMinY(label1.frame);
CGFloat label2Top = CGRectGetMinY(label2.frame);

return [@(label1Top) compare:@(label2Top)];
}];
}

Is IBOutletCollection guaranteed to be of correct order?

Both sources are sort of right: on one hand, due to the implementation details of the Interface Builder, the order in which you add items to IBOutletCollection will be maintained on retrieval; on the other hand, you should avoid making use of that ordering in your code, because there is no way to check this order.

Imagine taking over someone else's project. If you see a loop over an IBOutletCollection, observe that the order of iteration matters, and decide to check what that order is or force the new order, you would have to remove and re-add the controls to your outlet collection. That is why you should treat your IBOutletCollection elements as unordered. If it is necessary to maintain a specific order, copy the elements into an NSArray, sort them on some known property, and then iterate the copied collection.

Array of Outlets of type Label

You have to create IBOutlet Collection like as

@IBOutlet var labels: Array<UILabel>!

For more reference of code check this question :

1) Can't hook up an outlet collection in Xcode 6 using storyboard

2) Swift - IBOutletCollection equivalent

For example :

Sample Image

Swift: Set properties to an Extension of IBOutletCollection containing UIButtons

I have finally found the solution after so much trial and error. I want to share the answer with anybody that needs to set properties to UIButtons within an IBOutletCollection. This is a very efficient way to cut down time when you want to set/define properties to a group of buttons, or to all buttons project-wide.

I really hope someone finds this useful!

Code (Tested & Works): Note that what is in bold is what changed from the code I had in question.

//Inside the main viewController

@IBOutlet var ButtonCollection: [UIButton]!
//Inside the extention file:

extension Array where Element == UIButton
{
func sharedButtonProperties()
{
for **buttonGrp** in **self**
{
**buttonGrp**.setTitleColor(.red, for: .normal)
//MARK: More properties will go here now!
}
}
}
//calling the code inside main viewController, within "viewDidAppear"

ButtonCollection.sharedButtonProperties()

As you can see: I almost had it figured out, but all that was needed was to call the “buttonGrp” for the “for-in-loop", and to set this in “self”. I hope that makes sence!

Bye bye!

IBOutletCollection - how is ordering applied to the array?

You cannot use IBOutletCollection safely without adding an additional property like the tag if the ordering is important.

Sometimes they will retain the order in where the connections were added but sometimes they wont.

There are other similar questions that talk about this:

IBOutletCollection set ordering in Interface Builder

Register form with outlet collection and tags

This only will work if the order in the collection of TextFields is equal to the tags order

import UIKit

class ViewController: UIViewController,UITextFieldDelegate {

@IBOutlet var registerTF: [UITextField]!

func nextTag(currentTag:Int)->Int{

if(currentTag < registerTF!.count - 1){
return currentTag + 1
}
return -1
}

func nextTextFieldToFirstResponder(textField: UITextField) {

let nextTag = self.nextTag(currentTag: textField.tag)

if(nextTag >= 0){
self.registerTF![nextTag].becomeFirstResponder()
}else{
textField.resignFirstResponder()
}
}

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.nextTextFieldToFirstResponder(textField: textField)
return true
}

//LifeCycle-Starts

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.

for textField in registerTF {
textField.delegate = self
}
}

override func viewWillAppear(_ animated: Bool) {
//#
}

override func viewDidAppear(_ animated: Bool) {
//#
}

override func viewWillDisappear(_ animated: Bool) {
//#
}

override func viewDidDisappear(_ animated: Bool) {
//#
}

//LifeCycle-Ends

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}


Related Topics



Leave a reply



Submit