UserNotifications – Swift3 – utilizare

1. Import pentru UserNotifications framework si adaugam UNUserNotificationCenterDelegate in AppDelegate.swift
2. Implementare delegatii specifici pentru UNUserNotificationCenterDelegate in ViewController-ul dedicat sau folosind o extensie:
2.1.func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {
print("S-a apasat pe notificare, acum ar trebui implementantat ce anume se doreste dupa ce s-a dat click pe notificare")
}

2.2. func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
print("S-a primit notificare in foreground, definim aici actiunea care se va efectua in foregorund")

}
3. Cerere permisiuni de notificare din partea utilizatorului, de asemenea in AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// register user notification
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options:[.alert, .sound]) { (granted, error) in
}
return true
}

4. Delegarea actiunilor view-ului curent catre delegatii specifici: userNotificationCenter didReceive: si userNotificationCenter willPresent
UNUserNotificationCenter.current().delegate = self
5. Adaugam Observer care va “reactiona” atunci cand selectorul va “cere” sa efectueze o notificare:
NotificationCenter.default.addObserver(self, selector: #selector(numeMetodaNotificare()), name: NSNotification.Name(rawValue: "identificatorNumeNotificare"), object: nil)
6. Implementare metoda care va genera notificare numeMetodaNotificare()
func numeMetodaNotificare(output name:String)
{
let notification = UNMutableNotificationContent()
notification.title = NSString.localizedUserNotificationString(forKey: "Request received", arguments: nil)
notification.body = NSString.localizedUserNotificationString(forKey: "Request is: \(name)!", arguments: nil)
notification.sound = UNNotificationSound.default()
let request = UNNotificationRequest(identifier: "OneSecond", content: notification, trigger: nil)
let center = UNUserNotificationCenter.current()
print("s-a construit notificarea: \(notification.body)")
center.add(request)
}

Share Button

Swift3 – lucrul cu taskuri in background

Avem urmatorul scenariu: o aplicatie player audio care “observa” cand schimbam outputul audio: cand trecem de pe casti pe speaker si viceversa.
Nu intram in detalii aici cum e cu schimbarea rutei audio, poate intr-o discutie viitoare.
Ceea ce vreau sa punctez aici este urmatorul aspect: acest player poate functiona din IOS 8 si in background. Pot asculta muzica si atunci cand blochez ecranul sau comut pe alta aplicatie.
Cum pot permite unei aplicatii scrise in Swift3 sa “lucreze” si in background?

1. pot implementa metoda applicationWillResignActive(_ application: UIApplication)
2. putem inregistra notificarea UIApplicationWillResignActive oriunde in cadrul proiectului nostru Swift.

Cum facem lucrul asta:

1. func applicationWillResignActive(_ application: UIApplication) {
......
DispatchQueue.main.async {
self.backgroundUpdateTask = UIApplication.shared.beginBackgroundTask(expirationHandler: {
self.endBackgroundUpdateTask()
})
.....
}

2. NotificationCenter.default.addObserver(
self,
selector: #selector(appDidEnterBackground(notification:)),
name: .UIApplicationWillResignActive ,
object: nil)

unde definim selectorul astfel:

func appDidEnterBackground(notification: NSNotification) {
var bti:UIBackgroundTaskIdentifier=0
bti=self.app.beginBackgroundTask{
UIApplication.shared.endBackgroundTask(bti)
}

Le-am folosit pe ambele in aplicatii, insa o prefer pe a doua din motiv de claritate a codului. Nu e chiar ok sa abuzez de AppDelegate.

Share Button

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