Boas práticas no import

Muitas pessoas têm dúvidas sobre onde fazer o import das classes e frameworks em um projeto Objective-C. A primeira coisa a ser saber é:

Tudo que é importado no header(.h) já é automaticamente importado na implementação(.m), mas o contrário não.

Isso ocorre, pois sempre a implementação declara o import do header. O Xcode até faz isso de forma automática quando você cria uma nova classe. Esse import faz com que todo o import presente no header seja importado também pela implementação e isso pode trazer o risco de referências circulares (que será abordado também nesse artigo).

#import "MinhaClasse.h"

@implementation MinhaClasse

@end

Exemplo de um arquivo de implementação (MinhaClasse.m) gerado pelo Xcode


Variáveis/Property na implementação

O padrão é fazer o mínimo possível no header, pois ele é a sua interface pública. Portanto, a maioria dos imports de variável ou property devem ser feitos na implementação. Para todo caso que a property ou variável for usada somente na implementação(.m) e necessite de um import, faça o import na implementação, não no header. Como no exemplo abaixo:

//como não há nada que precise do import de Informacoes.h não
//faz sentido importar aqui
@interface MinhaClasse1 : NSObject
@end

MinhaClasse1.h

#import "MinhaClasse1.h"
#import "Informacoes.h"

@interface MinhaClasse1()
//declaração na implementação(.m) da property que precisa
//do import Informacoes.h
@property (strong, nonatomic) Informacoes info;
@end

@implementation MinhaClasse1
//implementação da classe
@end

MinhaClasse1.m


Variáveis no header

Quando se tem uma property no header que seja necessário fazer o import dela, deve-se usar a declaração @class no header e fazer o #import na implementação.

@class Informacoes;
@interface MinhaClasse2 : NSObject
@property (strong, nonatomic) Informacoes *info;
@end

MinhaClasse2.h

#import "MinhaClasse2.h"
#import "Informacoes.h"

@interface MinhaClasse2()
@end

@implementation MinhaClasse2
//implementação da classe
@end

MinhaClasse2.m

@class é como uma declaração antecipada; um aviso para que o compilador ainda não faça o import daquela classe, mas que ele pode ver uma referência à ela em algum momento. Caso o #import não seja feito na implementação (só exista o @class na interface) a propriedade ou método acessado na implementação exibirá o seguinte erro:

Property ‘nomePropriedade’ cannot be found in foward class object ‘NomeDaClasseSemImport’

Erro quando não se coloca o #import de uma property no arquivo .m

Receiver ‘NomeDaClasseSemImport’ for class message is a foward declaration

Erro quando não se coloca o #import de um método no arquivo .m

Essa medida é feita para deixar o que é importante (imports) mais próximo de onde é usado (implementação) e para evitar a criação de referências circulares. Referências circulares são quando um Objeto1.h faz o import do Objeto2 e ao mesmo tempo o Objeto2.h faz o import do Objeto1. Isso faz com que o compilador entre em loop ao compilar o código.


Classe Pai

Para fazer o #import da classe pai não é somente recomendado, mas necessário fazer o import no header. Para se declarar a classe pai, faça como no exemplo abaixo:

#import "NomeDaClassePai.h"

@interface MinhaClasse3 : NomeDaClassePai

@end

Exemplo de import da classe pai


Frameworks Apple

Ao se usar uma biblioteca ou framework alguns detalhes surgem. No iOS 7 (2013) a Apple lançou um novo import, o @import. Com esse import, não é necessário importar o framework nas configurações do projeto, isso é feito automaticamente. Por exemplo, ao usar o CoreLocations (para determinar a localização atual do usuário), e fazer uso do @import não é necessário fazer o passo abaixo:

addframework

Isso facilita o desenvolvedor, que só tem de declarar como abaixo:

@import <CoreLocation/CoreLocation.h>;

@interface MinhaClasse4 : UIViewController <CLLocationManagerDelegate>

@property (strong, nonatomic) CLLocationManager *locationManager;

@end

O único porém é que isso funciona mais com os frameworks da Apple.


Frameworks de terceiros

Para o caso de frameworks sem ser da Apple, o melhor a se fazer é seguir a documentação de quem criou. O Realm (banco de dados), por exemplo, deixa explícito em sua documentação que o framework deve ser importado e deve ser usado o #import <Realm/Realm.h>.

#import <Realm/Realm.h>;

@interface MinhaClasse5 : RLMObject

@property int id;
@property NSString *nome;

@end

A diferença entre #import Header.h e #import <Header.h> é que o primeiro busca o arquivo no local especificado, enquanto que o segundo busca em todos os diretórios referenciados como include. O segundo é usado por frameworks, pois assim o usuário não tem que incluir cada uma das suas interfaces públicas. Já o primeiro deve ser usado pelas classes de seu projeto, porém somente na implementação.

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s