Mostrando postagens com marcador Swift. Mostrar todas as postagens
Mostrando postagens com marcador Swift. Mostrar todas as postagens

terça-feira, 18 de setembro de 2018

Dicas de Programação: Enumeração em Swift

Uma coisa meio estranha no Swift, é que dá para colocar parâmetros dentro das "constantes" enumeradas e trabalhar com elas:

import Foundation

enum Log {
    //Constante debug com um parâmetro String
    case debug(String)
    //Constante warning com um parâmetro String
    case warning(String)
    //Constante error com um parâmetro String
    case error(String)
    //Função do enumerador que escreve no console/terminal
    func write() {
        //Obtém a data atual
        let now = Date()
        switch (self) {
         //Caso o enumerador seja debug 
        case Log.debug(let d):
           //Escreve na tela a data atual, a palavra [DEBUG] e o parâmetro "d" passado na constante
           print("\(now) [DEBUG] \(d)")
        //Caso o enumerador seja warning 
        case Log.warning(let w):
           //Escreve na tela a data atual, a palavra [WARNING] e o parâmetro "w" passado na constante
           print("\(now) [WARNING] \(w)")
        //Caso o enumerador seja error
        case Log.error(let e):
           //Escreve na tela a data atual, a palavra [ERROR] e o parâmetro "e" passado na constante
           print("\(now) [ERROR] \(e)")
        //Caso não seja nenhum deles, dá um erro
        default:
            fatalError("Unsupported")
        }
    }
} 
//Exemplo de uso
Log.error("Ocorreu um erro").write()
Log.warning("Variavel é nula, utilizando valor 0 como default").write()
let pi = 3.14
Log.debug("Valor da constante pi=\(pi)").write()

Bizarro, não?

Até mais!

sexta-feira, 14 de setembro de 2018

Dicas de programação: Reescrevendo operadores em Swift

Para reescrever operadores em Swift é bem simples: basta criar uma função estática com o "nome do operador", seus parâmetros e seu retorno (por exemplo, se for o operador ==, tenho dois parâmetros para comparar e um retorno do tipo booleano):

//Estrutura que guarda os dados de uma pessoa
struct Pessoa {
    //Nome da pessoa
    var nome: String

    //Idade da pessoa
    var idade: Int
    

    //Reescrevendo o operador ==
    static func ==(_ first: Pessoa, _ second:Pessoa) -> Bool {

        //Comparo o nome e a idade, se os dois forem iguais, retorno true, senão, retorno false
        return first.nome == second.nome && first.idade == second.idade
    }


}


//Crio os dados de uma pessoa
let pessoa1 = Pessoa(nome: "Ricardo Takemura", idade: Int.max)
//Crio os mesmos dados (em outro objeto)
let pessoa2 = Pessoa(nome: "Ricardo Takemura", idade: Int.max)

//Comparo um com o outro, se for igual exibo "{dado1} é igual que {dado2}" senão "{dado1} é diferente que {dado2}"
print("\(pessoa1) é \(pessoa1 == pessoa2 ? "igual" : "diferente") que \(pessoa2)")


Legal, não?

Até mais!

segunda-feira, 9 de julho de 2018

Dicas de Programação: Entendendo extensões em Swift

Extensões em Swift não são as coisas mais fáceis de se entender, mas não é um bicho de sete (7) cabeças. (se bem que bicho de sete cabeças não existe... eu acho... :P )

Extensões são, na prática, adições de métodos em classes já existentes.

Iremos a um exemplo, que isso torna as coisas mais fáceis. :)

Vamos dizer que eu precise, em meu projeto, botões que tenham, em sua característica, um fundo de cor gradiente, conforme ilustração:


Ok, neste caso, eu só tenho uma propriedade backgroundColor que coloca, ou imagem, ou uma cor sólida no botão...

Porém, eu sei que dá para fazer isso com um CAGradientLayer, adicionando esta como uma sublayer de uma UIView:

    override func viewDidAppear(_ animated: Bool) {
        let gradientLayer = CAGradientLayer()
        gradientLayer.colors = [UIColor.yellow, UIColor.green]
        gradientLayer.startPoint = CGPoint(x: 0, y: 0)
        gradientLayer.endPoint = CGPoint(x: 0, y: 1)
        gradientLayer.frame = CGRect(x: 0, y: 0, width: myButton.bounds.width, height:  myButton.bounds.height)
        myButton.layer.insertSublayer(gradientLayer, at: 0)
    }

Contudo, para cada botão que eu tiver na tela (ou telas) que precise de um gradiente, vou precisar usar o mesmo código...

Para evitar isso, que tal "adicionarmos" um método chamado "setGradientColors" em todos os botões (classe UIButton)?

Adicionar? Eureka! Como eu escrevi acima, é para isso que a extensão existe:

extension UIButton
{
    func setGradientColors(startColor: UIColor, endColor: UIColor) {
        let gradientLayer = CAGradientLayer()
        gradientLayer.colors = [startColor.cgColor, endColor.cgColor]
        gradientLayer.startPoint = CGPoint(x: 0, y: 0)
        gradientLayer.endPoint = CGPoint(x: 0, y: 1)
        gradientLayer.frame = CGRect(x: 0, y: 0, width: self.bounds.width, height: self.bounds.height)
        gradientLayer.type = kCAGradientLayerAxial
        if let sublayers = self.layer.sublayers {
            if (sublayers.count > 0) {
                let sublayer = sublayers[0]
                if (sublayer is CAGradientLayer) {
                    sublayer.removeFromSuperlayer()
                }
            }
        }
        self.layer.insertSublayer(gradientLayer, at: 0)
        self.layoutIfNeeded()
    }
}

Agora, para cada botão que precise usar um fundo gradiente, só é preciso chamar o método "setGradientColors":

override func viewDidAppear(_ animated: Bool) {
    myButton.setGradientColors(startColor: UIColor.yellow, endColor: UIColor.green)
}

Entretanto, você pergunta: Mas se eu quiser usar em um UILabel... Vou ter que criar a mesma função para esta classe?

Sim... e não! Se você quiser usar em todas as classes que herdam de UIView (UILabel e UIButton são filhos de UIView), você pode somente trocar a extensão de UIButton para UIView:

extension UIView
{
    func setGradientColors(startColor: UIColor, endColor: UIColor) {
        ...
    }
}

Que tudo vai funcionar! :)

Legal, né? Mas, como você pode ver, extensões são poderosas e, portanto, devem, sem dúvida nenhuma, serem utilizadas com cautela. (como diz tio Ben: "Com grandes poderes....")

Até mais!

quinta-feira, 25 de janeiro de 2018

Dicas de programação: Como gerar um Dictionary através de dois Arrays (Swift)?

Bem simples! Com o comando zip (a partir do iOS 8):

let fields = ["nome","sobrenome"]
let data = ["Ricardo", "Takemura"]
let union = zip(fields,data)
let dict = Dictionary(uniqueKeysWithValues: union)

Fácil, não? :P

Até mais!

quarta-feira, 18 de outubro de 2017

Como executar coisas nativas em Javascript em Swift no iOS?

Para isso, basta importar o framework JavaScriptCore no seu projeto. :P

Bem, tem mais passos:

import UIKit
import JavaScriptCore

//Protocolo para externalizar a função
@objc protocol MainJS: JSExport {
//Função log
static func log(_ text: String);
}

//View Controller
class MainViewController: UIViewController, UIWebViewDelegate, MainJS

//WebView
@IBOutlet weak var webView: UIWebView!

//Implementação da função log
static func log(_ text: String) {
       print("[\(Date())] - \(text)")
}

//Carregou a View? (função)
override fund viewDidLoad() {
       super.viewDidLoad()
       webView.delegate = self
      //Cria uma página html com um botão
       webView.loadHTMLString("<html><head></head><body><button onclick="native.log('teste');"></button></body></html>", baseURL: Bundle.main.bundleURL)
}

//Carregou a Página? (função)
func webViewDidFinishLoad(_ webView: UIWebView) {
     //Pego o contexto javascript da webView
      if let context = webView.value(forKeyPath: "documentView.webView.mainFrame.javaScriptContext") as! JSContext? {
             //Executa qualquer método que esta no protocolo MainJS através do objeto "native" do javascript
             //Exemplo: native.log('exemplo');
             context.setObject(MainViewController.self, forKeyedSubscript: "native" as (NSCopying & NSObjectProtocol)!)
      }
}