sendSynchronousRequest Swift 3

Am de migrat o aplicație din Swift 2.3 în Swift 3 pe un Deployment Target 10, adică aduc aplicația astfel încât ea sa folosească avantajele IOS 10+.
Aplicația pe care o upgradez folosește la un moment dat următoarea funcție de verificare în mod sincron a conectivității la server:


private func isServerReachable_Swift2() -> Bool {

        var Status:Bool = false

        let url = NSURL(string: "URL dorit")

        let request = NSMutableURLRequest(url: url! as URL)

        request.httpMethod = "POST"

        request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringLocalAndRemoteCacheData

        request.timeoutInterval = 10.0

        request.allowsCellularAccess = true

        var response: URLResponse?

        _ = (try? NSURLConnection.sendSynchronousRequest(request as URLRequest, returning: &response)) as NSData?

        if let httpResponse = response as? HTTPURLResponse {

            if httpResponse.statusCode == 200 {

                Status = true

                Log.d("server reachable")

            }

        }

        return Status;

    }

Ceea ce este depreciat în IOS 9+ este tocmai folosirea acestui sendSynchronousRequest(_:returning:). Corectă ar fi fost și folosirea unui try-catch pentru sendSynchronousRequest sub forma:

do {
    let data = try NSURLConnection.sendSynchronousRequest(request as URLRequest, returning: &response)
} catch (let e) {
    print(e)
}

Chiar dacă această problemă legată de synchronous este destul de delicată, SWIFT oferă întotdeauna o cale de a rezolva o astfel de problemă printr-un asynchronous pattern, adică prin adăugarea unui completion handler funcției mele.

Însă am preferat să explorez partea de Semaphores din SWIFT care mă va ajuta să realizez un request synchronous și să astept răspunsul de la server.

   private func isServerReachable() -> Bool {
        var status:Bool = false
        let dispatchSemaphore = DispatchSemaphore(value: 0)

        let url = NSURL(string: "URL dorit")
        let request = NSMutableURLRequest(url: url! as URL)
        request.httpMethod = "POST"
        request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringLocalAndRemoteCacheData
        request.timeoutInterval = 10.0
        request.allowsCellularAccess = true
        
        let task = URLSession.shared.dataTask(with: request as URLRequest, completionHandler: {data, response, error -> Void in
            if let httpResponse = response as? HTTPURLResponse {
                if httpResponse.statusCode == 200 {
                    status = true
                    dispatchSemaphore.signal()
                    Log.d("server reachable")
                }
            }
            
        })
        task.resume()
        // blochez thread-ul pana cand apare signal pe dispatchSemaphore
        dispatchSemaphore.wait()
        
        Log.d("Response in main thread status = \(status)")
        return status;
    }
Share Button

RemoveGestureRecognizer – SWIFT 3

Sunt într-o situație destul de inedită în care pe un subview – fullScreenConnectView –  am definit în viewDidLoad un TapGestureRecognizer pe care l-am atașat subview-ului.

        let gestureClickFullScreen = UITapGestureRecognizer(target: self, action:  #selector(self.connectClickFullScreen(_:)))

        self.fullScreenConnectView.addGestureRecognizer(gestureClickFullScreen)

Totul e bun și frumos însă trebuie la un moment dat sa elimin acest GestureRecognizer pe care l-am adaugat în viewDidLoad. Nu mai am de-a face cu instanța de UITapGestureRecognizer, aceasta existând doar în viewDidLoad. Poate o soluție pentru eliminarea TapGestureRecognizer este să-l declarat global. Însă am căutat o cale prin care să elimin acest TapGestureRecognizer fără să am acea instanță ținută inutil pe tot parcursul aplicației.

O soluție la îndemână pentru această problemă este: 

        self.fullScreenConnectView.gestureRecognizers?.forEach(self.fullScreenConnectView.removeGestureRecognizer)

Acest lucru este posibil deoarece agregatorul UIView.gestureRecognizers este în IOS 10 un vector, deci numai bun de parcurs și eliminat din el tot ce este în plus. 

    public var gestureRecognizers: [UIGestureRecognizer]?

Pe baza acestei ultime observații putem scrie un cod mai puțin swifty sub forma:

for recognizer in subview.gestureRecognizers ?? [ ] {
subview.removeGestureRecognizer(recognizer)
}

Share Button

Swift 3 – JSON – extragere informatii dintr-un fisier si transformare in Data

Avem urmatorul scenariu. Un fisier local ServerData.json care serveste continut pentru aplicatie; e o situatie putin atipica, in general content-ul vine din exterior.

Revenim, fisierul ServerData.json este adaugat in proiectul nostru si are in Target membership – File Inspector activat numele proiectului pentru a fi inclus la compilare.

Pentru a extrage informatiile din JSON si a le transforma in Data definim urmatoarea metoda:

 

public func dataFromFile(_ filename: String) -> Data? {

    @objc class TestClass: NSObject { }

    let bundle = Bundle(for: TestClass.self

    if let path = bundle.path(forResource: filename, ofType: “json”) {

        return (try? Data(contentsOf: URL(fileURLWithPath: path)))

    }

    return nil

}

bundle va fi un “container” care va incarca din path fisierul cu extensia json in caz ca exista (if let) urmand a obtine content-ul in format Data al json-ului.

 

Share Button

Lucrul cu DDXMLElement si DDXMLNode – Swift

Se da urmatorul XML generat:

{"message":"bubu","name":"tester","contact_id":"7","to":"tester"}


Vreau sa scot din XML nodul "message": "bubu"
Solutie:
1. do {
completeMessage = try element.nodes(forXPath: "body")
} catch _ {
completeMessage = [DDXMLNode]()
}

In acest moment completeMessage este sub forma vectoriala:
completeMessage - [{"message":"bubu","name":"tester","contact_id":"7","to":"tester"}]
2. let mesg = (completeMessage.first)?.child(at: 0)
let finalMessage = ((mesg?.stringValue)?.convertToDictionary())?["message"]

Extrag primul si singurul element din vector, il convertesc in dictionar si extrag campul “message”
finalMessage este in acest moment Optional(“bubu”) insa tipul este Any?
3. let bodyMessage = finalMessage as? String ?? ""
print("bodyMessage - \(bodyMessage)")

In acest moment am valoarea sub forma de string si anume “bubu”

Share Button

Swift 3 – Xcode -View – Aspect Fit, Aspect Fill si Scale To Fit

Nu de putine ori atunci cand adaugam o poza (image) intr-un ImageView Controller avem probleme cu dimensionarea acesteia. In mod normal o poza este deformata pentru a intra in ImageView si nu se tine cont de ratio in acest caz. E cazul VIEW -> MODE -> SCALE TO FIT

 

Daca vreau sa imi pastrez original ratio pentru poza astfel incat ea sa se incadreze in ImageView Controller-ul meu, solutia este VIEW -> MODE -> ASPECT FIT. Poza este corect redimensionata pe dimensiunea controller-ului.

 

O alta varianta ar fi l VIEW -> MODE -> ASPECT FILL, caz in care poza este incadrata pe original ratio insa nu se mai respecta granita ImageView-ului, imaginea fiind incadrata corect pe dimensiunea ecranului.

 

Share Button