I have MutableProperty. When I create new object I want to get current value of MutableProperty and start observing.
Such as:
let mutableProperty = MutableProperty<Driver?>(Driver(id: 1, name: "John"))
let label = UILabel()
label.text = mutableProperty.value?.name
mutableProperty.signal.observeNext{driver in
label.text = driver?.name
}
Is it possible write it better ?
If you want to use the value immediately:
let mutableProperty = MutableProperty<Driver?>(Driver(id: 1, name: "John"))
let label = UILabel()
mutableProperty.producer.startWithNext{ driver in
label.text = driver?.name
}
Related
Recently, I was working on a project of mine and I wanted to have multiple labels with the same font, text color, and properties, except their text.
This is the code I wrote:
lazy var profileLabel: UILabel = {
let label = UILabel()
label.font = .displayNameLabel
label.textColor = .profileLabel
label.numberOfLines = .numberOfLines
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
lazy var displayName: UILabel = {
let label = profileLabel
label.text = "Kevin"
return label
}()
lazy var countryLabel: UILabel = {
let label = profileLabel
label.text = "US"
return label
}()
As you can see, to remedy my issue, I created a single label that had all the properties I wanted for all my other labels. For my other labels, I thought I was creating a new label by typing let label = profileLabel. But as it turns out, I wasn't. After consecutive calls of setting the text and adding the labels to my view, only 1 label was actually displayed, and it was the last label added; so in this case, it would be the countryLabel.
It seems to me that in all my calls to let label = profileLabel, I'm just creating a reference to the same profileLabel. And if this is the case, would changing lazy var profileLabel to var profileLabel fix this issue and create a new label with the needed properties every time profileLabel is called?
You were intended to use computed property of swift. But didn’t get it right. Your profile label should have been defined as follows.
var profileLabel: UILabel {
get {
let label = UILabel()
label.font = .displayNameLabel
label.textColor = .profileLabel
label.numberOfLines = .numberOfLines
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
return label
}
}
I am trying to store a random number in a variable numberSelected and display it on a label created programmatically.I have the following code
var numberSelected = String()
let numbers = ["One", "Two", "Three", "Four"]
numberSelected = numbers.randomElement()!
let label = UILabel()
// Here text is being displayed
label.text = numbers.randomElement()
//Here text is not being displayed
label.text = numberSelected
print(label.text!)
How do I display the label using numberSelected variable? Thanks in advance.
Try this simple edit:
let numbers = ["One", "Two", "Three", "Four"]
let numberSelected = numbers.randomElement()!
let label = UILabel()
// This works
label.text = numbers.randomElement()
//This won't work
label.text = numberSelected
print(label.text!)
I have two UIButton if I click onto button1 the value of label1 is 250, if I click again onto button1 the value of label1 should be 0. The same logic is applied to my button2 and label2. I want to store the addition of label1 and label2 into label3. . My code is:
func PickUpCarCost() {
if (!isclick){
imgCheck.image = UIImage(named: "check.png")
isclick=true
//Pickup fare conver into integer
let PickUp = String(self.PickUpPrice)
PickUpFare.text = PickUp
self.pickCost = Int( PickUpFare.text!)
self.PAyAmount = ((self.PayFareWithSecurity)+(self.pickCost))
print("PaybleAmount: \(self.PAyAmount)")
self.AmountPay1 = ((self.PAyAmount)+(self.DeliverCost))
PaybleAmount.text=String(self.AmountPay1!)
}
else
{
imgCheck.image = UIImage(named: "uncheck.png")
PickUpFare.text = "0"
self.PickUpElse=Int(PickUpFare.text!)
print("PickUpElse: \(self.PickUpElse)")
self.PAyAmount = (self.PayFareWithSecurity)+(self.PickUpElse)
PaybleAmount.text=String(self.PAyAmount!)
isclick=false
}
}
func CarDeliverCost() {
if (!isclick){
imgUnCheck.image = UIImage(named: "check.png")
isclick=true
let DeliverPrice = String(self.deliveryPrice)
DeliverFare.text = DeliverPrice
self.DeliverCost = Int(DeliverFare.text!)
self.PAyAmount = ((self.PayFareWithSecurity)+(self.DeliverCost))
print("PaybleAmount: \(self.PAyAmount)")
PaybleAmount.text=String(self.PAyAmount!)
}
else
{
imgUnCheck.image = UIImage(named: "uncheck.png")
let deliveryelse = String(0)
DeliverFare.text = deliveryelse
self.deliver = Int(DeliverFare.text!)
PaybleAmount.text=String(self.PAyAmount!)
isclick=false
}
}
The first issue that you're facing is that you are using the same boolean isClick for two different scenarios. Your logic is that the user could decide to click onto both buttons or a single one. So if I click onto the first button then your flag is turn on, since the second button also uses the same boolean then you'll get that uncheck behavior automatically.
Thus you should use two different booleans such as hasPressOntoFirstButton and hasPressOntoSecondButton, where both set to false at the beginning, and each variable is used in their respective scene.
You mentioned that you want to add the label1 to label2, the easier way would be add the variable that set these labels. i.e
let label1 = UILabel()
let label2 = UILabel()
let label3 = UILabel()
let data1: Double = 83.0
let data2: Double = 82.0
var total: Double { // have a computed variable to adds automatically
return data1 + data2
}
label1.text = "\(data1)"
label2.text = "\(data2)"
label3.text = "\(data1 + data2)" // or "\(total)"
Remarks:
(1) your naming convention are really misleading, you should separate UI object naming from data. i.e you can have deliveryFareLabel.text instead of DeliverFare.text
(2) avoid using !, unwrapped all optional using either nil coalescing ??, or if let or guard statements
I have this array that I created: let yourShares = ["90%","40%", "23%","15%","10%"] Then to acess this:
for yourShare in yourShares {
dataSource[0].yourShareTitle = "90%"
dataSource[1].yourShareTitle = "40%"
dataSource[2].yourShareTitle = "23%"
dataSource[3].yourShareTitle = "10%"
}
Then to access this I put this code in an extension for collection view
let yourShare = model.dataSource?[indexPath.row]
cell.yourShareLabel.text = "Your Share \(yourShare!.yourShareTitle)"
cell.titleLabel?.font = UIFont.systemFont(ofSize: 1)
The problem is when I run this it just prints optional. Why, and how could I fix that? ~ Thanks
You need to unwrap it
if let yourShare = model.dataSource?[indexPath.row]?.yourShareTitle as? String {
cell.yourShareLabel.text = "Your Share \(yourShare)"
cell.titleLabel?.font = UIFont.systemFont(ofSize: 1)
}
var title: UILabel {
let label = UILabel()
textLabel.font = .systemFontOfSize(13)
return label
}
let title: UILabel = {
let label = UILabel()
textLabel.font = .systemFontOfSize(13)
return label
}()
lazy var title: UILabel = {
let label = UILabel()
textLabel.font = .systemFontOfSize(13)
return label
}()
If I put 'let' in the first one, compiler will complain that 'computed property do not allow let'. Ok, kind of makes sense. The only difference between the first one and second is '=' and '()'. So, does it mean that it is not a computed property anymore?
1.
var title: UILabel {
let label = UILabel()
textLabel.font = .systemFontOfSize(13)
return label
}
It is a read only computed property. Computed properties cannot be let. These are calculated using other stored/computed properties. So they don't have any backing store of their own. Hence, computed properties are always declared as var.
2.
let title: UILabel = {
let label = UILabel()
textLabel.font = .systemFontOfSize(13)
return label
}()
It is a stored property. This is assigned a closure that returns a UILabel object. This closure is executed during the instantiation process of the object and the returned UILabel object is assigned to title.
3.
lazy var title: UILabel = {
let label = UILabel()
textLabel.font = .systemFontOfSize(13)
return label
}()
It is a lazy stored property. It is also assigned a closure that returns a UILabel object. But this closure is not executed during the instantiation process. It is executed whenever this property is first used. After the execution of the closure, the UILabel object returned is assigned to title.
This is computed get-only property, it calculates every time when you try to get it value:
var title: UILabel {
let label = UILabel()
textLabel.font = .systemFontOfSize(13)
return label
}
This is regular property initialized immidiatly by in-place invoked closure (which playing default value role):
let title: UILabel = {
let label = UILabel()
textLabel.font = .systemFontOfSize(13)
return label
}()
This is lazy property, which will be initialized only on first access by in-place invoked closure:
lazy var title: UILabel = {
let label = UILabel()
textLabel.font = .systemFontOfSize(13)
return label
}()
In addition to all #PGDev has said, I would like to point out another way to write your second/third declaration:
Instead of:
let title: UILabel = {
let label = UILabel()
textLabel.font = .systemFontOfSize(13)
return label
}()
you can write:
let title: UILabel = {
$0.font = .systemFontOfSize(13)
return $0
}(UILabel())
It does exactly the same as the above, just the code is written differently :)