Advertisement
  1. Code
  2. iOS

iOS do princípio com Swift: Explorando o framework Foundation

Scroll to top
Read Time: 15 min
This post is part of a series called iOS From Scratch With Swift.
iOS From Scratch With Swift: Exploring the iOS SDK
iOS From Scratch With Swift: First Steps With UIKit

() translation by (you can also view the original English article)

O framework Foundation é o pão com manteiga da caixa de ferramentas do desenvolvedor iOS. Ele fornece a classe raiz NSObject e um grande número de blocos de construção fundamentais para o desenvolvimento iOS, de classes a números e strings, de arrays a dicionários. O framework Foundation pode parecer um pouco enroscado a primeira vista, mas ele aproveita bem o potência e é indispensável para o desenvolvimento de aplicativos iOS.

Uma palavra sobre Core Foundation

No artigo anterior, eu mencionei brevemente o Core Foundation e sua relação ao Foundation. Mesmo que não usaremos explicitamente o framework Core Foundation no restante desta série, é importante conhecer o framework e saber como ele se difere do seu irmão orientado a objetos, Foundation, que você usará extensivamente.

Enquanto o framework Foundation é implementado em Objective-C, o framework Core Foundation é baseado em C. Além desta diferença, o framework Core Foundation implementa um modelo de objeto limitado. Este modelo de objeto permite a definição de uma coleção de tipos opacos que são frequentemente referidos como objetos - apesar do fato de que eles não são, estritamente falando, objetos.

O principal objetivo de ambos os frameworks é semelhante, disponibilizar o compartilhamento de dados e código entre as várias bibliotecas e frameworks. O Core Foundation também inclui suporte à internacionalização. O componente chave para este suporte é fornecido através do tipo opaco CFString, que eficientemente administra um array de caracteres Unicode.

Como eu mencionei anteriormente, a transição toll-free literalmente preenche a lacuna entre ambos os frameworks habilitando a substituição dos objetos Cocoa por objetos Core Foundation em parâmetros de função e vice e versa.

É importante notar que o Automatic Reference Counting (ARC) não administra "objetos" Core Foundation. Isso significa que você é responsável por administrar a memória quando trabalha com Core Foundation. Mike Ash escreveu um ótimo artigo sobre o Automatic Reference Counting e como usar o ARC com o Core Foundation e a transição toll-free.

Visite o Core Foundation framework reference da Apple se você quiser aprender mais sobre o framework e para uma lista completa dos tipo opacos do framework.

Prática, Prática, Prática

A melhor forma de aprender uma nova habilidade é através da prática. Vamos começar criando um novo playground no Xcode. Chame o playground de Foundation e defina a Platform como iOS. Clique em Next para continuar. Informe ao Xcode onde você quer salvar o playground e clique em Create.

Creating a New PlaygroundCreating a New PlaygroundCreating a New Playground

Este é o conteúdo que virá no seu playground.

1
//: Playground - noun: a place where people can play

2
3
import UIKit
4
5
var str = "Hello, playground"

O playground contém um comentário no topo, uma instrução para importar o framework UIKit e uma declaração de variável. Na direita, você pode ver a saída do playground.

Já que iremos trabalhar com o framework Foundation, precisamos substituir a instrução import do UIKit pela instrução import do Foundation. Retire o comentario do topo, atualize a instrução import e remova a declaração da variável.

1
import Foundation

Foundation

O framework Foundation é muito mais que uma coleção de classes para se trabalhar com números, string e coleções (arrays, dicionários e sets). Ele também define uma dezena de protocolos, funções, tipo de dados e constantes.

No restante deste artigo, eu focarei principalmente nas classes que você usará frequentemente quando desenvolver aplicativos iOS. Entretanto, eu também falarei brevemente sobre os três protocolos chaves definidos no framework Foundation: NSObject, NSCoding e NSCopying.

Protocolos

Muitas linguagens, tais como Perl, Python e C++, fornecem suporte a herança múltipla. Isso significa que uma classe pode ser descendente - ser uma subclasse - de mais que uma classe.

Mesmo que o Swift e o Objective-C não forneçam suporte para herança múltipla, elas suportam herança múltipla através de uma especificação na forma de protocolos. Nós já falamos sobre protocolos anteriormente nesta série, mas há um detalhe importante que não discutimos ainda.

Métodos obrigatórios e opcionais

Relembre que todo método de um protocolo Swift é obrigatório. Se um tipo em conformidade com um protocolo Swift não implementar cada propriedade e método definido pelo protocolo, o compilador irá lançar um erro. Isso já não é igual para os protocolos do Objetive-C. Em Objective-C, os métodos de um protocolo podem ser marcados como opcionais. Se um método de protocolo for opcional, o tipo em conformidade com o protocolo não é obrigado a implementar o método.

Por conta disso a grande maioria dos frameworks do SDK do iOS são escritos em Objetive-C, iremos encontrar uma grande quantidade de protocolos Objetive-C que definem métodos opcionais. O que é importante de se lembrar é que toda propriedade e método de um protocolo Swift é obrigatório.

Benefícios

Os protocolos tem múltiplos benefícios. Quando uma classe adota ou fica em conformidade com um protocolo, espera-se que a classe implemente o método declarado pelo protocolo. Para alguns de vocês, protocolos podem lembrar as interfaces do Java. Isso significa que um protocolo pode ser usado para declarar a interface de um objeto sem revelar o tipo do objeto.

Herança multipla tem seus benefícios, mas certamente tem seu lado negativo. A vantagem dos protocolos é que tipos, enums, classes e estruturas não relacionados, ainda podem compartilhar um comportamento semelhante por meio do uso de protocolos.

NSObject

Em adição a classe raiz NSObject, o framework Foundation também define o protocolo NSObject. Em Swift, entretanto, classes e protocolos não podem ter o mesmo nome. Como resultado, o protocolo NSObject é chamado de NSObjectProtocolo em Swift.

Objetos em conformidade com o protocolo NSObjectProtocol podem ser chamados pelas suas classes e subclasse, podem ser comparados com outros objetos e reponder ao self. Este é apenas um pequeno subconjunto dos comportamentos adicionados aos objetos em conformidade com o protocolo NSObjectProtocol.

NSCoding

Objetos em conformidade com o protocolo NSCoding podem ser codificados e decodificados. Isso é necessario para objetos que precisem ser arquivos ou distribuídos. Objetos de arquivos, por exemplo, acorre quando um objeto ou objeto gráfico é armazenado em disco.

NSCopying

O protocolo NSCopying declara apenas um método, copyWithZone(_:). Se uma classe der suporte a copia de objetos, ela precisa estar em conformidade com o protocolo NSCopying. A copia de um objeto é feita enviando ele a mensagem do copy() ou copyWithZone(_:).

Classes

NSObject

A classe NSObject é a classe raiz da grande maioria das hierarquias de classes do Objective-C. Por que isso é importante se estamos interessados em Swift? Lembre-se que a maioria dos frameworks do SDK do iOS são construídos em cima do Objective-C. Mesmo se você decidir desenvolver um aplicativo em Swift, você ainda usará Objective-C por baixo dos panos.

Por serem herdeiras da classe raiz NSObject, os objetos sabem se comportar como objetos Objective-C e como fazer a interface com o Objective-C em tempo de execução. Não deve ser surpresa que o NSObject esta em conformidade com o protocolo NSObject/NSObjectProtocol, que discutimos a alguns minutos atrás.

Vamos ver o que ganhamos se uma classe herda da classe NSObject. Adicione o seguinte trecho de código em seu playground. Isso lhe será familiar se você leu o artigo anterior desta série. Declaramos uma classe, Book, que herda da NSObject. A classe Book implementa dois métodos de instância, chapters() e pages().

1
class Book: NSObject {
2
    func chapters() {
3
        
4
    }
5
    
6
    func pages() {
7
        
8
    }
9
}

Como o Book herda da classe NSObject e o NSObject está em conformidade com o protocolo NSObjectProtocol, podemos perguntar à classe Book sobre seus comportamentos e suas árvore de herança. Dê uma olhada no exemplo a seguir.

Inspecting the Book ClassInspecting the Book ClassInspecting the Book Class

Primeiro perguntamos à classe Book sobre ela mesmo chamando classForCoder() na classe Book. O método classForCorder() é um método de classe, o que significa que podemos chamar este método na própria classe Book. Em seguida, perguntamos a classe Book sobre sua superclasse ou classe pai, a classe que ela herda diretamente. Esta retorna um opcional, já que nem todas as classe tem uma classe pai. Sem surpresa, a superclasse da Book é NSObject.

A próxima linha nos diz que a Book esta em conformidade com o protocolo NSObjectProtocol, o que não é inesperado já que ela herda este traço da classe NSObject. Nós também aprendemos que a Book não está em conformidade com o protocolo NSCoding.

Parece que a classe Book não responde ao método chapters(). Isso não é estranho já que o chapters() é um método de instância e não um método de classe.  Isso é comprovado com as ultimas duas linhas do nosso exemplo em que instanciamos uma instância da Book e perguntando à instância a mesma coisa.

No exemplo acima usamos o método respondsToSelector(_:), mas você pode estar se perguntando o que é o seletor? O que "respondendo a um seletor" significa?  Um seletor é um apelido para o nome de uma função ou método. Um seletor é usado pelo Objective-C em tempo de execução para enviar mensagens aos objetos. Encurtando essa história, se você ler a palavra seletor, então pense em função ou método. Os detalhes estão além do escopo deste tutorial.

NSNumber

A classe NSNumber é uma classe de utilidade que gerência qualquer tipo básico de dados numéricos. Ela é uma subclasse da classe NSValue, que fornece um pacote orientado a objetos para tipos escalares, ponteiros, estruturas e objetos ids. A classe NSNumber define métodos para recuperar valores nele armazenados, para comparação de valores e também para retornar uma string representando o valor armazenado.

Tenha em mente que os valores recuperados por uma instância NSNumber precisam ser consistentes com o valor que será armazenado nele. A classe NSNumber tentará converter dinamicamente o valor armazenado para o tipo solicitado, mas é evidente que existem limitações inerentes aos tipos de dados que NSNumber pode gerenciar.

Deixe-me ilustrar isto com um exemplo. Adicione o seguinte trecho de código ao seu playground.

Working With the NSNumber ClassWorking With the NSNumber ClassWorking With the NSNumber Class

Nós criamos uma nova instância da NSNumber passando um valor Double para init(double:). Em seguida, solicitamos o valor armazenado usando três diferentes métodos da NSNumber. Como você pode ver, o resultado nem sempre reflete o valor armazenado na myNumber.

A lição é simples, ser consistente quando usar o NSNumber mantendo o controle do tipo que for armazenado na instância do NSNumber.

NSString

Instâncias da classe NSString administra um array de caracteres unichar formando uma string de texto. A sutil, mas importante diferença com a habitual string C, que administra caracteres char, é que um caracter unichar é um caracter multibyte. Isso é semelhante para o tipo String do Swift.

Como seu nome implica, um caracter unichar é ideal para a manipulação de caracteres Unicode. Devido a essa implementação, a classe NSString fornece suporte para internacionalização fora da caixa.

Eu quero enfatizar que a string administrada por uma instância da NSString é imutável. Isso significa que, uma vez que a string for criada, ela não pode ser modificada. Desenvolvedores vindos de outras linguagens, tais como PHP, Ruby ou JavaScript, podem ficar confusos com este comportamento.

O framework Foundation também define uma subclasse mutável do NSString, o NSMutableString, que pode ser modificado após inicializado.

Há várias maneiras de criar objetos de string. A maneira mais simples de criar um objeto de string é chamando o método string() da classe NSString. Isso retorna um objeto de string em branco. Dê uma olhada na referência de classe do NSString para uma lista completa de inicializadores.

Outro caminho comum para a criação de objetos de string é através das literais. No próximo exemplo, um literal é atribuída para a stringA. Em tempo de compilação, o compilador substituirá a liberal com uma instância da NSString.

Creating Strings in SwiftCreating Strings in SwiftCreating Strings in Swift

Note que não utilizamos a inferência de tipo do Swift para determinar o tipo da stringA. O segundo exemplo, stringB, demonstra por que isso.  Se não especificarmos explicitamente o tipo da stringA como NSString, o Swift entenderá que queremos criar uma instância String. O exemplo também ilustra que a NSString herda da NSObject, enquanto a String não. Lembre-se que o tipo String do Swift é uma estrutura e estruturas não comportam herança.

A classe NSString tem uma grande quantidade de instâncias e métodos de classe para criar e manipular string e você raramente, ou nunca, irá sentir a necessidade de usar a classe NSString.

Vamos explorar NSString e sua subclasse mutável, NSMutableString, adicionando o trecho de código a seguir em seu playground.

1
let stringA: NSString = "This is "
2
let stringB: NSString = NSString(string: "a mutable string.")
3
4
var mutableString = NSMutableString(string: stringA)
5
mutableString.appendString(stringB as String)

Iniciamos criando duas instâncias da NSString, uma usando a sintaxe literal e uma usando o inicializador init(String:). Uma string mutável é então criada passando a primeira string como argumento. Para demostrar que string mutáveis podem ser modificadas após sua criação, a stringB é acrescentada à string mutável e o seu valor impresso.

NSArray e NSSet.

A classe NSArray gerência uma lista ordenada imutável de objetos. O framework Foundation também define uma subclasse mutável do NSArray, NSMutableArray. A classe NSArray se comporta muito parecida com um array do C ou do Swift, com a diferença que um instância NSArray gerência objetos. A classe NSArray declara uma grande quantidade de método que facilita o trabalho com arrays, tais como métodos para busca e ordenação de objetos no array.

É importante entender que instâncias de NSArray, NSSet e NSDictionary podem armazenar apenas objetos. Isso significa que não é possível armazenar tipos escalares, ponteiros ou estruturas em qualquer coleção de classes - ou suas subclasses - o compilador irá lançar um erro se você tentar. A solução é empacotar os tipos escalares, ponteiros e estruturas em uma instância de NSValue ou NSNumber como nós vimos anteriormente neste artigo.

Adicione o seguinte trecho de código em seu playground para explorar o NSArray e sua versão mutável, NSMutableArray.

1
let myArray = NSArray(objects: "Bread", "Butter", "Milk", "Eggs")
2
print(myArray.count)
3
print(myArray.objectAtIndex(2))
4
5
var myMutableArray = NSMutableArray(object: NSNumber(int: 265))
6
myMutableArray.addObject(NSNumber(int: 45))

Criamos um array usando o inicializador init(objects:). Este método recebe um número variável de argumentos. Em seguida, imprimimos o número de objetos do array e perguntamos ao array pelo seu objeto no índice 2.

Como o NSMutableArray herda do NSArray, ele se comporta da mesma forma que o NSArray. A principal diferente é que objetos podem ser adicionados e removidos do array após ser inicializado.

Antes de prosseguir, quero dizer algumas palavras sobre NSSet. Esta classe é similar ao NSArray, mas sua diferença chave é que a coleção de objetos que um set gerência é desordenada e que um set não pode conter valor duplicados.

A vantagem do NSSet é que o acesso a seus objetos é rápido se você precisa apenas saber se um objeto existe no set. O framework Foundation também define o NSOrderedSet. Instâncias desta classe tem o beneficio do NSSet, mas também guarda rastro da localização de cada objeto.

NSDictionary

Como os arrays, dicionários é um conceito comum na maioria das linguagens de programação. Em Ruby, por exemplo, eles são referidos como hashes. O conceito básico é simples, um dicionário gerência uma coleção estática de pares valor/chave ou entradas.

Como as hashes em Ruby, a chave de uma entrada não precisa ser necessariamente um objeto de string. Ele pode ser qualquer tipo de objeto que esteja em conformidade com o protocolo NSCopying, desde que a chave seja única no dicionário. Na maioria dos casos, é recomendando usar objetos de string como chave.

Como os arrays, os dicionários não podem armazenar um valor nulo. Se você quiser representar um valor nulo, então você pode usar o NSNull. A classe NSNull define um objeto singleton que é usado para simbolizar valores nulos em arrays, dicionários e sets.

O padrão singleton é um padrão importante em muitas linguagens de programação. Ele limita a instanciação de uma classe para um objeto. Você irá lidar com objetos singleton frequentemente quando estiver desenvolvendo aplicativos iOS.

Como no NSArray, o framework Foundation define uma subclasse mutável do NSDictionary, o NSMutableDictionary. Há várias formas de instanciar um dicionário. Dê uma olhada no trecho de código a seguir.

1
let keyA: NSString = "myKey"
2
let keyB: NSString = "myKey"
3
4
let myDictionary = NSDictionary(object: "This is a string literal", forKey: keyA)
5
6
print(myDictionary.objectForKey(keyB))

Declaramos dois objetos NSString separados contendo a mesma string. Então instanciamos um dicionário chamando o init(object:forKey:). Em seguida, perguntamos ao dicionário pelo objeto associado com o conteúdo do keyB e imprimimos o seu valor.

É importante ter atenção nos detalhes. Apesar de termos usados a keyA como chave do par chave/valor e a keyB como chave da busca do valor ou objeto do par chave/valor, o dicionário nos deu o objeto correto (como um opcional). A classe NSDictionary é inteligente o suficiente para saber que queremos o objeto associado com a string "myKey". O que isso significa? Mesmo os objetos keyA e keyB serem objetos diferentes, a string que eles contêm é a mesma e justamente é a que a classe NSDictionary usa para referenciar o objeto.

Antes de finalizar este tutorial, eu gostaria de mostrar um exemplo de encadeamento de dicionários e array e um exemplo do NSMutableDictionary. O fragmento de código a seguir mostra que um dicionário pode conter outro dicionário, ou array, e ele também demonstra como trabalhar com dicionários mutáveis.

1
let myMutableDictionary = NSMutableDictionary()
2
myMutableDictionary.setObject(myDictionary, forKey: "myDictionary")

Conclusão

Apesar de termos coberto uma grande área de terreno neste artigo, nós mal arranhamos a superfície do que o framework Foundation tem para nos oferecer. Não é necessario saber os detalhes de todas as classes ou funções definidas no framework Foundation para começar com o desenvolvimento iOS. Irei ensinara mais sobre o framework Foundation conforme você explorar o SDK do iOS.

No próximo artigo, exploraremos o framework UIKit e eu também discutirei as entradas e saídas de um aplicativo iOS.

Se você tiver alguma pergunta ou comentário, você pode deixa-los nos comentários abaixo ou me procurar no Twitter.

Seja o primeiro a saber sobre novas traduções–siga @tutsplus_pt no Twitter!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.