Nil-Coalescing Operator – Swift

Nu stiu cum sa-i zic pe romaneste acestui operator ?? in Swift. De doua ori semnul intrebarii ar suna ridicol.
Documentatia Apple spune ca a ?? b este prescurtarea de la
a != nil ? a! : b
Ce ar insemna asta?
Daca a nu este nil atunci forteaza pe a sa devina a! – valoare unwrapped, in caz contrar, adica daca a este nil, a devenind b.

Ca sa intelegem mai bine, dam un mic exemplu:

let defaultColorName = "red"
var userDefinedColorName: String? // defaults to nil
var colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName is nil, so colorNameToUse is set to the default of "red"

userDefinedColorName este implicit nil atunci cand se face initializarea.
Var-ul colorNameToUse ia valoarea userDefinedColorName daca nu este nil (nu este cazul) si in acest caz va lua valoarea defaultColorName.

Share Button

Transmiterea unei imagini in format base64 catre server in Swift3

Avem o imagine. O transformam in string pentru a o putea transfera catre un server tert:

let image = UIImage(...)
let imageData = UIImageJPEGRepresentation(image!, 0.7)
let imageString:String = imageData!.base64EncodedString(options: NSData.Base64EncodingOptions.lineLength64Characters) as String

Ca si observatie, e important sa stabilim optiunea lineLength64Characters pentru codarea imaginii, acesta fiind formatul folosit de un server Apache pentru decodarea base64.

Avem deci in acest moment un string ce contine o imagine pe care dorim sa o trimitem spre un server web.

Folosim un request de tip POST in care specificam metoda de codare x-www-form-urlencoded:

request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")

In momentul in care facem request-ul totul este frumos in aplicatia IOS insa pe server toate caracterele “+” sunt codate ” ” adica blank space. Nimeni nu ar observa acest lucru, mai ales ca nu apare nici un warning, nici o eroare pe device-ul IOS. Insa server-side, la decodificarea stringului base64 receptionat vom avea o eroare din cauza faptului ca nu poate fi scoasa imaginea de acolo.

Solutia?

Trebuie sa inlocuim in stringul base64 caracterul “+” cu “%2b” inainte de a face request-ul catre serverul web:

paramsStr = paramsStr.replacingOccurrences(of: "+", with: "%2b")

Share Button

prepare(for:sender:) – apelare de doua ori?

Sunt in urmatorul scenariu: un buton din ViewController-ul A – VCA este legat prin segue cu prezentare modala de un ViewController B – VCB.

In VCA am definit metoda prepare(for:sender:)
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "asSegue" {
.....
}

Practic definesc ce anume fac atunci cand se va produce click pe butonul ce va aduce modalul VCB.

Din exces de zel fac urmatoarea greseala: In VCA, deci in ViewControllerul mama spun ca atunci cand se da click pe butonul care are atasat segue sa activez urmatoarea metoda:
performSegue(withIdentifier: "visibilitiesSegue", sender: self)

Totul merge bine si frumos, la click pe butonul din VCA apare modalul VCB, imi fac treaba si e perfect! Numai ca in consola am un pic warning:
Warning: Attempt to present VCB on VCA which is already presenting (null)
Nu m-ar deranja prea tare daca nu as vrea sa am consola curata de warning-uri.

Caut la Apple despre performSegue si aflu ca
“Normally, segues are initiated automatically and not using this method.”

Ce gresesc?

Metoda prepare(for:sender:) este apelata de doua ori, o data automat atunci cand eu dau click si se produce implicit prezentarea lui VCB si a doua oara cand eu i-am specificat faptul ca la click de buton trebuie sa activeze performSegue(withIdentifier:sender:)

Solutia?

Elimin de la executie performSegue(withIdentifier:sender:) deoarece atunci cand se face click pe buton pentru a prezenta VCB automat este executata prepare(for:sender:)

Share Button

Poate fi atasat un UIGestureRecognizer la mai multe view-uri?

Cei de la Apple spun ca nu: un UIGestureRecognizer poate fi utilizat doar cu un singur view.
Cum trecem peste acest impediment, avand o lista de view-uri, fiecare din aceste view-uri facand aceeasi actiune, sa zicem tiparirea campului tag?

1. generam o functie care va returna un UIGestureRecognizer

func setGestureRecognizer() -> UITapGestureRecognizer {
var gesture = UITapGestureRecognizer()
gesture = UITapGestureRecognizer(target: self, action: #selector(changeImage(sender:)))
return gesture
}

2. definim functia de raspuns in care extragem view-ul senderul UIImageView
func changeImage(sender: UITapGestureRecognizer) {
let tappedImageView = sender.view! as? UIImageView
print("button clicked - \(tappedImageView!.tag)")
}

3. folosim recognizer-ul in view-urile noastre
view1.addGestureRecognizer(setGestureRecognizer())
view2.addGestureRecognizer(setGestureRecognizer())
view3.addGestureRecognizer(setGestureRecognizer())

Share Button

Warning – Expression of type ‘UIViewController?’ is unused

Atunci cand folosesc intr-o alerta pentru ramura de close o expresie de genul: navigationController?.popViewController(animated: true)

XCode 8 imi genereaza un warning de genul: Expression of type ‘UIViewController?’ is unused.

Adica eu iti returnez un UIViewController? si tu nu vrei sa-l folosesti de nici un fel?

Pana la Swift 3 toate functiile aveau implicit “discardable result”. Adica daca nu foloseai explicit outputul functiei, nici o problema.

La Swift 3 dispare aceasta “facilitate” tocmai pentru a preintampina situatiile in care returnul functiei este “uitat” de coderi.

Pentru a remedia acest warning este suficient sa rescriu utilizarea astfel:

let _ = navigationController?.popViewController(animated: true)

Share Button