Give buttons same behavior (twins) - ios

I would like my UIButtons to interact with each other - (With the corresponding button)
First set of buttons;
#IBOutlet var P1button1: UIButton!
#IBOutlet var P1button2: UIButton!
#IBOutlet var P1button3: UIButton!
#IBOutlet var P1button4: UIButton!
#IBOutlet var P1button5: UIButton!
#IBOutlet var P1button6: UIButton!
#IBOutlet var P1button7: UIButton!
#IBOutlet var P1button8: UIButton!
#IBOutlet var P1button9: UIButton!
Second set of buttons;
#IBOutlet var P2button1: UIButton!
#IBOutlet var P2button2: UIButton!
#IBOutlet var P2button3: UIButton!
#IBOutlet var P2button4: UIButton!
#IBOutlet var P2button5: UIButton!
#IBOutlet var P2button6: UIButton!
#IBOutlet var P2button7: UIButton!
#IBOutlet var P2button8: UIButton!
#IBOutlet var P2button9: UIButton!
In my code I apply an Image to one random P1button from an Array;
var buttons = [P1button1, P1button2, P1button3, P1button4, P1button5, P1button6, P1button7, P1button8, P1button9]
buttons.shuffleInPlace()
buttons[0].setImage(UIImage(named: "Green"), forState: .Normal)
Now, I want to know if there is a way to make the P2buttons "co-operate" with the P1buttons. Meaning that if an Image is applied to P1button1 then P2button1 is set to the same image! (and so forth for all buttons)
Example;
P2button1.setImage = UIImage(P1button1)
This obviously doesn't work but hopefully gives you a clue about what I'm trying to achieve.

One possible approach would be by subclassing UIButton. Perhaps something like this...
class TwinButton {
weak var twin: TwinButton?
}
Now, in your viewDidLoad method, link up all of the twins.
p1button1.twin = p2button1
p2button1.twin = p1button1
Now, I'd write a set of methods that have some "with twin" semantics...
extension TwinButton {
setWithTwin(title: String)
setWithTwin(backgroundImage: UIImage)
}
and those methods simply set the value on self and twin.

Related

Put multiple UILabels into an array

In my app I currently have 9 labels on my storyboard, each showing a different value. (The values are stored in an array). As far as I know, each label has to be connected from the storyboard to the viewcontroller file separately, which makes my code look like this:
#IBOutlet weak var xValue: UILabel!
#IBOutlet weak var yValue: UILabel!
#IBOutlet weak var zValue: UILabel!
#IBOutlet weak var maxXValue: UILabel!
#IBOutlet weak var maxYValue: UILabel!
#IBOutlet weak var maxZValue: UILabel!
#IBOutlet weak var minXValue: UILabel!
#IBOutlet weak var minYValue: UILabel!
#IBOutlet weak var minZValue: UILabel!
And to set the values, I need to manually do:
xValue.text = arr[0]
yValue.text = arr[1]
...
minYValue = arr[7]
minZValue = arr[8]
Is there a way to connect multiple labels from the storyboard into an array so that I can simply do something like:
for i in 0...8 {
labelArray[i] = arr[i]
}
As rmaddy mentioned in a comment you can use an outlet collection:
#IBOutlet private var labels: [UILabel]!
Then in your storyboard labels will show up under Outlet Collections when right-clicking your ViewController, and you can link multiple labels:
You can put all the UILabel into an array, like this:
let labelArray = [xValue, yValue, zValue]
for i in 0..<labelArray.count-1{
labelArray[i] = arr[i]
}

Changing the image of a button based on control state

I am trying to change the image of a button when clicked, they are stars like a rating system. when clicked the image remains the same and does not change when clicked. I set the default image in story board.
class DetailViewController: UIViewController {
#IBOutlet weak var detailTitleViewLbl: UILabel!
#IBOutlet weak var detailDescription: UILabel!
#IBOutlet weak var yearLabel: UILabel!
#IBOutlet weak var star1: UIButton!
#IBOutlet weak var star2: UIButton!
#IBOutlet weak var star3: UIButton!
#IBOutlet weak var star4: UIButton!
#IBOutlet weak var star5: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func star1Pressed() {
star1.setImage(#imageLiteral(resourceName: "favorite (1).png"), for: UIControlState.selected)
}
func star2Pressed() {}
func star3pressed() {}
func star4pressed() {}
}
A button doesn't change to the selected state when clicked. You need to write code that sets the button's selected flag to true when it's clicked.
Note that you can connect more than one IBAction to a button, so you could have one action that sets the selected flag to true, and another that does custom "stuff", so you don't have to duplicate the "boilerplate" code to set the selected state in the IBAction of every such button.

Clean up code? (Xcode freezes at indexing)

I believe I have to clean up my code a bit, since Xcode for the first time started to freeze at "indexing" and I can't run my project. I think it's easy to do, but I don't know what way is the best. Got 36 UIImageViews...
#IBOutlet var Image1: UIImageView!
#IBOutlet var Image2: UIImageView!
#IBOutlet var Image3: UIImageView!
#IBOutlet var Image4: UIImageView!
#IBOutlet var Image5: UIImageView!
#IBOutlet var Image6: UIImageView!
#IBOutlet var Image7: UIImageView!
#IBOutlet var Image8: UIImageView!
#IBOutlet var Image9: UIImageView!
#IBOutlet var Image10: UIImageView!
#IBOutlet var Image11: UIImageView!
#IBOutlet var Image12: UIImageView!
#IBOutlet var Image13: UIImageView!
#IBOutlet var Image14: UIImageView!
#IBOutlet var Image15: UIImageView!
#IBOutlet var Image16: UIImageView!
#IBOutlet var Image17: UIImageView!
#IBOutlet var Image18: UIImageView!
#IBOutlet var Image19: UIImageView!
#IBOutlet var Image20: UIImageView!
#IBOutlet var Image21: UIImageView!
#IBOutlet var Image22: UIImageView!
#IBOutlet var Image23: UIImageView!
#IBOutlet var Image24: UIImageView!
#IBOutlet var Image25: UIImageView!
#IBOutlet var Image26: UIImageView!
#IBOutlet var Image27: UIImageView!
#IBOutlet var Image28: UIImageView!
#IBOutlet var Image29: UIImageView!
#IBOutlet var Image30: UIImageView!
#IBOutlet var Image31: UIImageView!
#IBOutlet var Image32: UIImageView!
#IBOutlet var Image33: UIImageView!
#IBOutlet var Image34: UIImageView!
#IBOutlet var Image35: UIImageView!
#IBOutlet var Image36: UIImageView!
override func viewDidLoad() {
let images = (1...6).map { UIImage(named: "Owl\($0)") }
let imageViewsArray = [Image1, Image2, Image3, Image4, Image5, Image6, Image7, Image8, Image9, Image10, Image11, Image12, Image13, Image14, Image15, Image16, Image17, Image18, Image19, Image20, Image21, Image22, Image23, Image24, Image25, Image26, Image27, Image28, Image29, Image30, Image31, Image32, Image33, Image34, Image35, Image36]
for view in imageViewsArray {
let randomIndex = Int(arc4random_uniform(UInt32(images.count)))
view.image = images[randomIndex]
}
}
Could I make an IBOutlet for all 36 images together? Or something like this? :-)
Info about the code in ViewDidLoad() here.
As #FruitAddict said, an UICollectionView may be useful, depending of what you want to display of course. But if it doesn't fit your needs, you can still use an Outlet connection instead of an outlet :
Thus you can access every labels directly from labelCollection, which is an explicit unwrapped array of UILabel.
Also, in the gif, the second label is added to the collection outlet by draging it to the already existing outlet. The outlet is not replaced (as in a regular object), but instead the new label is added to the array.
EDIT :
As #nhgrif pointed out, don't rely on the order of the objects within the outlet collection :
It's important to note that while many times the order within the outlet collection may coincidentally coincide with the order you dragged them in, Apple makes no guarantees about this and the order within the collection should not be relied upon.
You should consider this array as a set.

'Expected declaration' error in init function (swift)

Can someone help me figure out why I can't fix this error in Swift using Xcode6? I'm trying to initialize all my buttons so they aren't nil and it's telling me I'm not declaring something when I thought I was. Any suggestions? The required init method line is giving me the error.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var displayLabel: UILabel!
#IBOutlet weak var buttonOne: UIButton!
#IBOutlet weak var buttonTwo: UIButton!
#IBOutlet weak var buttonThree: UIButton!
#IBOutlet weak var buttonClear: UIButton!
#IBOutlet weak var buttonFour: UIButton!
#IBOutlet weak var buttonFive: UIButton!
#IBOutlet weak var buttonSix: UIButton!
#IBOutlet weak var buttonX: UIButton!
#IBOutlet weak var buttonSeven: UIButton!
#IBOutlet weak var buttonEight: UIButton!
#IBOutlet weak var buttonNine: UIButton!
#IBOutlet weak var buttonDiv: UIButton!
#IBOutlet weak var buttonPlus: UIButton!
#IBOutlet weak var buttonZero: UIButton!
#IBOutlet weak var buttonMin: UIButton!
#IBOutlet weak var buttonEq: UIButton!
#IBOutlet weak var buttonSet: UIButton!
var userIsTyping: Bool = false
required init(coder aDecoder: NSCoder) {
displayLabel = UILabel()
buttonOne = UIButton()
buttonTwo = UIButton()
buttonThree = UIButton()
buttonFour = UIButton()
buttonFive = UIButton()
buttonSix = UIButton()
buttonSeven = UIButton()
buttonEight = UIButton()
buttonNine = UIButton()
buttonZero = UIButton()
buttonClear = UIButton()
buttonX = UIButton()
buttonPlus = UIButton()
buttonDiv = UIButton()
buttonMin = UIButton()
buttonEq = UIButton()
buttonSet = UIButton()
super.init(coder: aDecoder)
}
From Apple documentation:
An outlet is a property of an object that references another object. The reference is archived through Interface Builder. The connections between the containing object and its outlets are reestablished every time the containing object is unarchived from its nib file. The containing object holds an outlet declared as a property with the type qualifier of IBOutlet and a weak option.
So, you should not instantiate a #IBOutlet object, since they are meant to be connected to a UI object on storyboard or .nib file.
You've said that you are doing this to avoid nil pointer. When does that happen?

Collection of Collection of UIViews

In my Swift app I have 9 outlets:
#IBOutlet weak var day1: UIImageView!
#IBOutlet weak var day1Title: UILabel!
#IBOutlet weak var day1Description: UILabel!
#IBOutlet weak var day2: UIImageView!
#IBOutlet weak var day2Title: UILabel!
#IBOutlet weak var day2Description: UILabel!
#IBOutlet weak var day3: UIImageView!
#IBOutlet weak var day3Title: UILabel!
#IBOutlet weak var day3Description: UILabel!
I'd like to "group" these together by their day using an integer as the key. So 1 maps to day1, day1Title, day1Description.
So that I could assign label text to each of the above generically rather than have to reference the specific image view, label, and description.
Any thoughts/suggestions?
I thought maybe:
Dictionary<int, Array<UIImageView, UILabel, UILabel>>
or
Dictionary<int, Array<UIView>>
but i'm not quite sure about this being the right move. Could I somehow assign a class that has 3 properties that reference these outlets maybe?
Or perhaps 3 outlet collections?
What do you think is good to do?
Thanks!
Why use a dictionary with an integer key? An array of 9 elements should work just as well. In addition, the value would be better represented as a tuple instead of as an array.
Array<(UIImageView, UILabel, UILabel)>
or
[(UIImageView, UILabel, UILabel)]
result
var views: [(UIImageView, UILabel, UILabel)]
…
views = [(day1, day1Title, day1Description),
(day2, day2Title, day2Description),
…
(day9, day9Title, day9Description)]
…
var (imageView, titleLabel, descriptionLabel) = views[dayNumber - 1]

Resources