Guia rápido de Objective-C
Objective-C é uma linguagem de propósito geral desenvolvida em cima da linguagem de programação C, adicionando recursos da linguagem de programação Small Talk, tornando-a uma linguagem orientada a objetos. É usado principalmente no desenvolvimento de sistemas operacionais iOS e Mac OS X, bem como em seus aplicativos.
Inicialmente, Objective-C foi desenvolvido pela NeXT para seu sistema operacional NeXTSTEP, de quem foi adquirido pela Apple para seu iOS e Mac OS X.
Programação Orientada a Objetos
Suporta totalmente a programação orientada a objetos, incluindo os quatro pilares do desenvolvimento orientado a objetos -
- Encapsulation
- Ocultação de dados
- Inheritance
- Polymorphism
Código de exemplo
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSLog (@"hello world");
[pool drain];
return 0;
}
Estrutura da Fundação
O Foundation Framework fornece um grande conjunto de recursos e eles estão listados abaixo.
Inclui uma lista de tipos de dados estendidos como NSArray, NSDictionary, NSSet e assim por diante.
Consiste em um rico conjunto de funções de manipulação de arquivos, strings, etc.
Ele fornece recursos para tratamento de URL, utilitários como formatação de data, tratamento de dados, tratamento de erros, etc.
Objetivo de Aprendizagem-C
A coisa mais importante a fazer ao aprender Objective-C é focar nos conceitos e não se perder nos detalhes técnicos da linguagem.
O objetivo de aprender uma linguagem de programação é se tornar um programador melhor; isto é, para se tornar mais eficaz no projeto e implementação de novos sistemas e na manutenção dos antigos.
Uso de Objective-C
Objective-C, como mencionado anteriormente, é usado no iOS e Mac OS X. Ele tem uma grande base de usuários iOS e um número cada vez maior de usuários Mac OS X. E já que a Apple foca primeiro na qualidade e é maravilhoso para aqueles que começaram a aprender Objective-C.
Configuração de ambiente local
Se você ainda deseja configurar seu ambiente para a linguagem de programação Objective-C, você precisa dos dois softwares a seguir disponíveis em seu computador, (a) Editor de Texto e (b) Compilador GCC.
Editor de texto
Isso será usado para digitar seu programa. Exemplos de poucos editores incluem o bloco de notas do Windows, o comando Editar do sistema operacional, Brief, Epsilon, EMACS e vim ou vi.
O nome e a versão do editor de texto podem variar em diferentes sistemas operacionais. Por exemplo, o Bloco de notas será usado no Windows e o vim ou vi pode ser usado no Windows, bem como no Linux ou UNIX.
Os arquivos que você cria com seu editor são chamados de arquivos-fonte e contêm o código-fonte do programa. Os arquivos de origem para programas Objective-C são normalmente nomeados com a extensão ".m"
Antes de iniciar sua programação, certifique-se de ter um editor de texto instalado e de ter experiência suficiente para escrever um programa de computador, salvá-lo em um arquivo, compilá-lo e finalmente executá-lo.
O compilador GCC
O código-fonte escrito no arquivo-fonte é a fonte legível para o seu programa. Ele precisa ser "compilado" para se transformar em linguagem de máquina, para que sua CPU possa realmente executar o programa de acordo com as instruções fornecidas.
Este compilador GCC será usado para compilar seu código-fonte no programa executável final. Presumo que você tenha conhecimento básico sobre um compilador de linguagem de programação.
O compilador GCC está disponível gratuitamente em várias plataformas e o procedimento para configurar em várias plataformas é explicado abaixo.
Instalação em UNIX / Linux
A etapa inicial é instalar o gcc junto com o pacote gcc Objective-C. Isso é feito por -
$ su - $ yum install gcc
$ yum install gcc-objc
A próxima etapa é configurar as dependências do pacote usando o seguinte comando -
$ yum install make libpng libpng-devel libtiff libtiff-devel libobjc
libxml2 libxml2-devel libX11-devel libXt-devel libjpeg libjpeg-devel
Para obter todos os recursos do Objective-C, baixe e instale o GNUStep. Isso pode ser feito baixando o pacote dehttp://main.gnustep.org/resources/downloads.php.
Agora, precisamos mudar para a pasta baixada e descompactar o arquivo -
$ tar xvfz gnustep-startup-
.tar.gz
Agora, precisamos mudar para a pasta gnustep-startup que foi criada usando -
$ cd gnustep-startup-<version>
Em seguida, precisamos configurar o processo de construção -
$ ./configure
Então, podemos construir por -
$ make
Precisamos finalmente configurar o ambiente por -
$ . /usr/GNUstep/System/Library/Makefiles/GNUstep.sh
Temos um helloWorld.m Objective-C da seguinte forma -
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSLog (@"hello world");
[pool drain];
return 0;
}
Agora, podemos compilar e executar um arquivo Objective-C, digamos helloWorld.m, alternando para a pasta que contém o arquivo usando cd e, em seguida, seguindo os seguintes passos -
$ gcc `gnustep-config --objc-flags`
-L/usr/GNUstep/Local/Library/Libraries
-lgnustep-base helloWorld.m -o helloWorld
$ ./helloWorld
Podemos ver a seguinte saída -
2013-09-07 10:48:39.772 tutorialsPoint[12906] hello world
Instalação em Mac OS
Se você usa Mac OS X, a maneira mais fácil de obter o GCC é baixar o ambiente de desenvolvimento Xcode do site da Apple e seguir as instruções de instalação simples. Depois de configurar o Xcode, você poderá usar o compilador GNU para C / C ++.
O Xcode está disponível atualmente em developer.apple.com/technologies/tools/ .
Instalação em Windows
Para executar o programa Objective-C no Windows, precisamos instalar o MinGW e o GNUStep Core. Ambos estão disponíveis emhttps://www.gnu.org/software/gnustep/windows/installer.html.
Primeiro, precisamos instalar o pacote do sistema MSYS / MinGW. Então, precisamos instalar o pacote GNUstep Core. Ambos fornecem um instalador do Windows, que é autoexplicativo.
Então, para usar Objective-C e GNUstep, selecionando Iniciar -> Todos os Programas -> GNUstep -> Shell
Mude para a pasta que contém helloWorld.m
Podemos compilar o programa usando -
$ gcc `gnustep-config --objc-flags`
-L /GNUstep/System/Library/Libraries hello.m -o hello -lgnustep-base -lobjc
Podemos executar o programa usando -
./hello.exe
Obtemos a seguinte saída -
2013-09-07 10:48:39.772 tutorialsPoint[1200] hello world
Antes de estudarmos os blocos de construção básicos da linguagem de programação Objective-C, vamos examinar uma estrutura mínima de programa Objective-C para que possamos tomá-la como uma referência nos próximos capítulos.
Exemplo de Objective-C Hello World
Um programa Objective-C consiste basicamente nas seguintes partes -
- Comandos do pré-processador
- Interface
- Implementation
- Method
- Variables
- Declarações e Expressões
- Comments
Vejamos um código simples que imprimiria as palavras "Hello World" -
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
- (void)sampleMethod;
@end
@implementation SampleClass
- (void)sampleMethod {
NSLog(@"Hello, World! \n");
}
@end
int main() {
/* my first program in Objective-C */
SampleClass *sampleClass = [[SampleClass alloc]init];
[sampleClass sampleMethod];
return 0;
}
Vejamos várias partes do programa acima -
A primeira linha do programa #import <Foundation / Foundation.h> é um comando de pré-processador, que diz a um compilador Objective-C para incluir o arquivo Foundation.h antes de ir para a compilação real.
A próxima linha @interface SampleClass: NSObject mostra como criar uma interface. Ele herda NSObject, que é a classe base de todos os objetos.
A próxima linha - (void) sampleMethod; mostra como declarar um método.
A próxima linha @end marca o fim de uma interface.
A próxima linha @implementation SampleClass mostra como implementar a interface SampleClass.
A próxima linha - (void) sampleMethod {} mostra a implementação do sampleMethod.
A próxima linha @end marca o fim de uma implementação.
A próxima linha int main () é a função principal onde a execução do programa começa.
A próxima linha /*...*/ será ignorada pelo compilador e foi colocada para adicionar comentários adicionais no programa. Portanto, essas linhas são chamadas de comentários no programa.
A próxima linha NSLog (...) é outra função disponível em Objective-C que causa a mensagem "Hello, World!" a ser exibido na tela.
A próxima linha return 0; termina a função main () e retorna o valor 0.
Compilar e executar o programa Objective-C
Agora, quando compilarmos e executarmos o programa, obteremos o seguinte resultado.
2017-10-06 07:48:32.020 demo[65832] Hello, World!
Você viu uma estrutura básica do programa Objective-C, então será fácil entender outros blocos de construção básicos da linguagem de programação Objective-C.
Tokens em Objective-C
Um programa Objective-C consiste em vários tokens e um token é uma palavra-chave, um identificador, uma constante, um literal de string ou um símbolo. Por exemplo, a seguinte declaração Objective-C consiste em seis tokens -
NSLog(@"Hello, World! \n");
Os tokens individuais são -
NSLog
@
(
"Hello, World! \n"
)
;
Ponto e vírgula;
No programa Objective-C, o ponto-e-vírgula é um terminador de instrução. Ou seja, cada declaração individual deve terminar com um ponto e vírgula. Indica o fim de uma entidade lógica.
Por exemplo, a seguir estão duas declarações diferentes -
NSLog(@"Hello, World! \n");
return 0;
Comentários
Os comentários são como texto de ajuda em seu programa Objective-C e são ignorados pelo compilador. Eles começam com / * e terminam com os caracteres * / conforme mostrado abaixo -
/* my first program in Objective-C */
Você não pode ter comentários em comentários e eles não ocorrem em uma string ou em literais de caracteres.
Identificadores
Um identificador Objective-C é um nome usado para identificar uma variável, função ou qualquer outro item definido pelo usuário. Um identificador começa com uma letra de A a Z ou a a z ou um sublinhado _ seguido por zero ou mais letras, sublinhados e dígitos (0 a 9).
Objective-C não permite caracteres de pontuação como @, $ e% nos identificadores. Objective-C é umcase-sensitivelinguagem de programação. Assim, Manpower e manpower são dois identificadores diferentes em Objective-C. Aqui estão alguns exemplos de identificadores aceitáveis -
mohd zara abc move_name a_123
myname50 _temp j a23b9 retVal
Palavras-chave
A lista a seguir mostra algumas das palavras reservadas em Objective-C. Essas palavras reservadas não podem ser usadas como constantes ou variáveis ou quaisquer outros nomes de identificador.
auto | outro | grandes | interruptor |
pausa | enum | registro | typedef |
caso | externo | Retorna | União |
Caracteres | flutuador | baixo | não assinado |
const | para | assinado | vazio |
continuar | vamos para | tamanho de | volátil |
padrão | E se | estático | enquanto |
Faz | int | estrutura | _Packed |
em dobro | protocolo | interface | implementação |
NSObject | NSInteger | NSNumber | CGFloat |
propriedade | não atômico; | reter | Forte |
fraco | unsafe_unretained; | ler escrever | somente leitura |
Espaço em branco em Objective-C
Uma linha contendo apenas espaços em branco, possivelmente com um comentário, é conhecida como uma linha em branco, e um compilador Objective-C a ignora totalmente.
Espaço em branco é o termo usado em Objective-C para descrever espaços em branco, tabulações, caracteres de nova linha e comentários. O espaço em branco separa uma parte de uma instrução de outra e permite que o compilador identifique onde um elemento em uma instrução, como int, termina e o próximo elemento começa. Portanto, na seguinte declaração -
int age;
Deve haver pelo menos um caractere de espaço em branco (geralmente um espaço) entre int e age para que o compilador seja capaz de distingui-los. Por outro lado, na seguinte declaração,
fruit = apples + oranges; // get the total fruit
Nenhum caractere de espaço em branco é necessário entre frutas e =, ou entre = e maçãs, embora você seja livre para incluir alguns se desejar para fins de legibilidade.
Na linguagem de programação Objective-C, os tipos de dados referem-se a um sistema extenso usado para declarar variáveis ou funções de diferentes tipos. O tipo de uma variável determina quanto espaço ela ocupa no armazenamento e como o padrão de bits armazenado é interpretado.
Os tipos em Objective-C podem ser classificados da seguinte forma -
Sr. Não. | Tipos e descrição |
---|---|
1 | Basic Types − Eles são tipos aritméticos e consistem em dois tipos: (a) tipos inteiros e (b) tipos de ponto flutuante. |
2 | Enumerated types − Eles são novamente tipos aritméticos e são usados para definir variáveis que só podem ser atribuídas a certos valores inteiros discretos em todo o programa. |
3 | The type void − O especificador de tipo void indica que nenhum valor está disponível. |
4 | Derived types − Eles incluem (a) tipos de ponteiro, (b) tipos de matriz, (c) tipos de estrutura, (d) tipos de união e (e) tipos de função. |
Os tipos de matriz e tipos de estrutura são chamados coletivamente de tipos agregados. O tipo de uma função especifica o tipo do valor de retorno da função. Veremos os tipos básicos na seção seguinte, enquanto outros tipos serão abordados nos próximos capítulos.
Tipos inteiros
A tabela a seguir fornece detalhes sobre os tipos inteiros padrão com seus tamanhos de armazenamento e intervalos de valores -
Tipo | Tamanho de armazenamento | Faixa de valor |
---|---|---|
Caracteres | 1 byte | -128 a 127 ou 0 a 255 |
caracter não identifcado | 1 byte | 0 a 255 |
char assinado | 1 byte | -128 a 127 |
int | 2 ou 4 bytes | -32.768 a 32.767 ou -2.147.483.648 a 2.147.483.647 |
int não assinado | 2 ou 4 bytes | 0 a 65.535 ou 0 a 4.294.967.295 |
baixo | 2 bytes | -32.768 a 32.767 |
curto sem sinal | 2 bytes | 0 a 65.535 |
grandes | 4 bytes | -2.147.483.648 a 2.147.483.647 |
longo sem sinal | 4 bytes | 0 a 4.294.967.295 |
Para obter o tamanho exato de um tipo ou variável em uma plataforma específica, você pode usar o sizeofoperador. A expressão sizeof (tipo) fornece o tamanho de armazenamento do objeto ou tipo em bytes. A seguir está um exemplo para obter o tamanho do tipo int em qualquer máquina -
#import <Foundation/Foundation.h>
int main() {
NSLog(@"Storage size for int : %d \n", sizeof(int));
return 0;
}
Quando você compila e executa o programa acima, ele produz o seguinte resultado no Linux -
2013-09-07 22:21:39.155 demo[1340] Storage size for int : 4
Tipos de ponto flutuante
A tabela a seguir fornece detalhes sobre os tipos de ponto flutuante padrão com tamanhos de armazenamento e intervalos de valor e sua precisão -
Tipo | Tamanho de armazenamento | Faixa de valor | Precisão |
---|---|---|---|
flutuador | 4 bytes | 1.2E-38 a 3.4E + 38 | 6 casas decimais |
em dobro | 8 bytes | 2,3E-308 a 1,7E + 308 | 15 casas decimais |
longo duplo | 10 bytes | 3.4E-4932 a 1.1E + 4932 | 19 casas decimais |
O arquivo de cabeçalho float.h define macros que permitem que você use esses valores e outros detalhes sobre a representação binária de números reais em seus programas. O exemplo a seguir imprimirá o espaço de armazenamento ocupado por um tipo flutuante e seus valores de intervalo -
#import <Foundation/Foundation.h>
int main() {
NSLog(@"Storage size for float : %d \n", sizeof(float));
return 0;
}
Quando você compila e executa o programa acima, ele produz o seguinte resultado no Linux -
2013-09-07 22:22:21.729 demo[3927] Storage size for float : 4
O tipo vazio
O tipo void especifica que nenhum valor está disponível. É usado em três tipos de situações -
Sr. Não. | Tipos e descrição |
---|---|
1 | Function returns as void Existem várias funções em Objective-C que não retornam valor ou você pode dizer que retornam void. Uma função sem valor de retorno tem o tipo de retorno nulo. Por exemplo,void exit (int status); |
2 | Function arguments as void Existem várias funções em Objective-C que não aceitam nenhum parâmetro. Uma função sem parâmetro pode ser aceita como nula. Por exemplo,int rand(void); |
O tipo de vazio pode não ser compreendido por você neste ponto, então vamos prosseguir e abordaremos esses conceitos nos próximos capítulos.
Uma variável nada mais é que um nome dado a uma área de armazenamento que nossos programas podem manipular. Cada variável em Objective-C possui um tipo específico, que determina o tamanho e o layout da memória da variável; a faixa de valores que podem ser armazenados nessa memória; e o conjunto de operações que podem ser aplicadas à variável.
O nome de uma variável pode ser composto de letras, dígitos e o caractere de sublinhado. Deve começar com uma letra ou um sublinhado. Letras maiúsculas e minúsculas são diferentes porque Objective-C diferencia maiúsculas de minúsculas. Com base nos tipos básicos explicados no capítulo anterior, haverá os seguintes tipos básicos de variáveis -
Sr. Não. | Tipo e descrição |
---|---|
1 | char Normalmente, um único octeto (um byte). Este é um tipo inteiro. |
2 | int O tamanho mais natural do inteiro para a máquina. |
3 | float Um valor de ponto flutuante de precisão única. |
4 | double Um valor de ponto flutuante de precisão dupla. |
5 | void Representa a ausência de tipo. |
A linguagem de programação Objective-C também permite definir vários outros tipos de variáveis, que abordaremos em capítulos subsequentes como Enumeração, Ponteiro, Matriz, Estrutura, União, etc. Para este capítulo, vamos estudar apenas os tipos básicos de variáveis.
Definição de Variável em Objective-C
Uma definição de variável significa dizer ao compilador onde e quanto criar o armazenamento para a variável. Uma definição de variável especifica um tipo de dados e contém uma lista de uma ou mais variáveis desse tipo da seguinte forma -
type variable_list;
Aqui, type deve ser um tipo de dados Objective-C válido, incluindo char, w_char, int, float, double, bool ou qualquer objeto definido pelo usuário, etc., e variable_listpode consistir em um ou mais nomes de identificadores separados por vírgulas. Algumas declarações válidas são mostradas aqui -
int i, j, k;
char c, ch;
float f, salary;
double d;
A linha int i, j, k;ambos declaram e definem as variáveis i, j e k; que instrui o compilador a criar variáveis chamadas i, j e k do tipo int.
As variáveis podem ser inicializadas (atribuídas a um valor inicial) em sua declaração. O inicializador consiste em um sinal de igual seguido por uma expressão constante da seguinte maneira -
type variable_name = value;
Alguns exemplos são -
extern int d = 3, f = 5; // declaration of d and f.
int d = 3, f = 5; // definition and initializing d and f.
byte z = 22; // definition and initializes z.
char x = 'x'; // the variable x has the value 'x'.
Para definição sem um inicializador: variáveis com duração de armazenamento estático são inicializadas implicitamente com NULL (todos os bytes têm o valor 0); o valor inicial de todas as outras variáveis é indefinido.
Declaração de variável em Objective-C
Uma declaração de variável fornece garantia ao compilador de que existe uma variável com o tipo e nome fornecidos para que o compilador prossiga para a compilação posterior sem precisar de detalhes completos sobre a variável. Uma declaração de variável tem seu significado apenas no momento da compilação, o compilador precisa da declaração da variável real no momento da vinculação do programa.
Uma declaração de variável é útil quando você está usando vários arquivos e define sua variável em um dos arquivos, que estará disponível no momento da vinculação do programa. Você vai usarexternpalavra-chave para declarar uma variável em qualquer lugar. Embora você possa declarar uma variável várias vezes em seu programa Objective-C, ela pode ser definida apenas uma vez em um arquivo, função ou bloco de código.
Exemplo
Tente o exemplo a seguir, onde as variáveis foram declaradas no topo, mas foram definidas e inicializadas dentro da função principal -
#import <Foundation/Foundation.h>
// Variable declaration:
extern int a, b;
extern int c;
extern float f;
int main () {
/* variable definition: */
int a, b;
int c;
float f;
/* actual initialization */
a = 10;
b = 20;
c = a + b;
NSLog(@"value of c : %d \n", c);
f = 70.0/3.0;
NSLog(@"value of f : %f \n", f);
return 0;
}
Quando o código acima é compilado e executado, ele produz o seguinte resultado -
2013-09-07 22:43:31.695 demo[14019] value of c : 30
2013-09-07 22:43:31.695 demo[14019] value of f : 23.333334
O mesmo conceito se aplica à declaração de função, onde você fornece um nome de função no momento de sua declaração e sua definição real pode ser fornecida em qualquer outro lugar. No exemplo a seguir, é explicado usando a função C e, como você sabe, Objective-C também suporta funções de estilo C -
// function declaration
int func();
int main() {
// function call
int i = func();
}
// function definition
int func() {
return 0;
}
Lvalues e Rvalues em Objective-C
Existem dois tipos de expressões em Objective-C -
lvalue- As expressões que se referem a um local da memória são chamadas de expressão "lvalue". Um lvalue pode aparecer como o lado esquerdo ou direito de uma atribuição.
rvalue- O termo rvalue se refere a um valor de dados que é armazenado em algum endereço da memória. Um rvalue é uma expressão que não pode ter um valor atribuído a ela, o que significa que um rvalue pode aparecer no lado direito, mas não no lado esquerdo de uma atribuição.
As variáveis são lvalues e, portanto, podem aparecer no lado esquerdo de uma atribuição. Literais numéricos são rvalues e, portanto, não podem ser atribuídos e não podem aparecer no lado esquerdo. A seguir está uma declaração válida -
int g = 20;
Mas a seguir não é uma declaração válida e geraria um erro em tempo de compilação -
10 = 20;
As constantes referem-se a valores fixos que o programa não pode alterar durante sua execução. Esses valores fixos também são chamadosliterals.
As constantes podem ser de qualquer um dos tipos básicos de dados, como uma constante inteira, uma constante flutuante, uma constante de caractere ou um literal de string . Também existem constantes de enumeração.
o constants são tratadas como variáveis regulares, exceto que seus valores não podem ser modificados após sua definição.
Literais inteiros
Um literal inteiro pode ser uma constante decimal, octal ou hexadecimal. Um prefixo especifica a base ou raiz: 0x ou 0X para hexadecimal, 0 para octal e nada para decimal.
Um literal inteiro também pode ter um sufixo que é uma combinação de U e L, para sem sinal e longo, respectivamente. O sufixo pode ser maiúsculo ou minúsculo e pode estar em qualquer ordem.
Aqui estão alguns exemplos de literais inteiros -
212 /* Legal */
215u /* Legal */
0xFeeL /* Legal */
078 /* Illegal: 8 is not an octal digit */
032UU /* Illegal: cannot repeat a suffix */
A seguir estão outros exemplos de vários tipos de literais inteiros -
85 /* decimal */
0213 /* octal */
0x4b /* hexadecimal */
30 /* int */
30u /* unsigned int */
30l /* long */
30ul /* unsigned long */
Literais de ponto flutuante
Um literal de ponto flutuante possui uma parte inteira, um ponto decimal, uma parte fracionária e uma parte expoente. Você pode representar literais de ponto flutuante na forma decimal ou exponencial.
Ao representar usando a forma decimal, você deve incluir a vírgula decimal, o expoente ou ambos e, ao representar usando a forma exponencial, você deve incluir a parte inteira, a parte fracionária ou ambas. O expoente assinado é introduzido por e ou E.
Aqui estão alguns exemplos de literais de ponto flutuante -
3.14159 /* Legal */
314159E-5L /* Legal */
510E /* Illegal: incomplete exponent */
210f /* Illegal: no decimal or exponent */
.e55 /* Illegal: missing integer or fraction */
Constantes de personagem
Literais de caracteres são colocados entre aspas simples, por exemplo, 'x' e podem ser armazenados em uma variável simples de char tipo.
Um literal de caractere pode ser um caractere simples (por exemplo, 'x'), uma seqüência de escape (por exemplo, '\ t') ou um caractere universal (por exemplo, '\ u02C0').
Existem certos caracteres em C quando eles são precedidos por uma barra invertida, eles terão um significado especial e são usados para representar como nova linha (\ n) ou tabulação (\ t). Aqui, você tem uma lista de alguns desses códigos de sequência de escape -
Sequência de fuga | Significado |
---|---|
\\ | \ personagem |
\ ' | ' personagem |
\ " | " personagem |
\? | ? personagem |
\uma | Alerta ou sino |
\ b | Backspace |
\ f | Feed de formulário |
\ n | Nova linha |
\ r | Retorno de carruagem |
\ t | Aba horizontal |
\ v | Aba vertical |
\ ooo | Número octal de um a três dígitos |
\ xhh. . . | Número hexadecimal de um ou mais dígitos |
A seguir está o exemplo para mostrar alguns caracteres de sequência de escape -
#import <Foundation/Foundation.h>
int main() {
NSLog(@"Hello\tWorld\n\n");
return 0;
}
Quando o código acima é compilado e executado, ele produz o seguinte resultado -
2013-09-07 22:17:17.923 demo[17871] Hello World
Literais de string
Literais ou constantes de string são colocados entre aspas duplas "". Uma string contém caracteres semelhantes aos literais de caracteres: caracteres simples, sequências de escape e caracteres universais.
Você pode quebrar uma linha longa em várias linhas usando literais de string e separando-as usando espaços em branco.
Aqui estão alguns exemplos de literais de string. Todas as três formas são strings idênticas.
"hello, dear"
"hello, \
dear"
"hello, " "d" "ear"
Definindo Constantes
Existem duas maneiras simples em C de definir constantes -
Usando #define pré-processador.
Usando const palavra-chave.
O pré-processador #define
A seguir está o formulário para usar o pré-processador #define para definir uma constante -
#define identifier value
O exemplo a seguir explica em detalhes -
#import <Foundation/Foundation.h>
#define LENGTH 10
#define WIDTH 5
#define NEWLINE '\n'
int main() {
int area;
area = LENGTH * WIDTH;
NSLog(@"value of area : %d", area);
NSLog(@"%c", NEWLINE);
return 0;
}
Quando o código acima é compilado e executado, ele produz o seguinte resultado -
2013-09-07 22:18:16.637 demo[21460] value of area : 50
2013-09-07 22:18:16.638 demo[21460]
A palavra-chave const
Você pode usar const prefixo para declarar constantes com um tipo específico da seguinte forma -
const type variable = value;
O exemplo a seguir explica em detalhes -
#import <Foundation/Foundation.h>
int main() {
const int LENGTH = 10;
const int WIDTH = 5;
const char NEWLINE = '\n';
int area;
area = LENGTH * WIDTH;
NSLog(@"value of area : %d", area);
NSLog(@"%c", NEWLINE);
return 0;
}
Quando o código acima é compilado e executado, ele produz o seguinte resultado -
2013-09-07 22:19:24.780 demo[25621] value of area : 50
2013-09-07 22:19:24.781 demo[25621]
Observe que é uma boa prática de programação definir constantes em MAIÚSCULAS.
Um operador é um símbolo que informa ao compilador para executar manipulações matemáticas ou lógicas específicas. A linguagem Objective-C é rica em operadores integrados e fornece os seguintes tipos de operadores -
- Operadores aritméticos
- Operadores Relacionais
- Operadores lógicos
- Operadores bit a bit
- Operadores de atribuição
- Operadores diversos
Este tutorial irá explicar os operadores aritméticos, relacionais, lógicos, bit a bit, atribuição e outros, um por um.
Operadores aritméticos
A tabela a seguir mostra todos os operadores aritméticos suportados pela linguagem Objective-C. Assumir variávelA contém 10 e variável B contém 20, então -
Mostrar exemplos
Operador | Descrição | Exemplo |
---|---|---|
+ | Adiciona dois operandos | A + B dará 30 |
- | Subtrai o segundo operando do primeiro | A - B dará -10 |
* | Multiplica ambos os operandos | A * B dará 200 |
/ | Divide numerador por denominador | B / A dará 2 |
% | Operador de Módulo e o restante após uma divisão inteira | B% A dará 0 |
++ | O operador de incremento aumenta o valor inteiro em um | A ++ dará 11 |
- | Operador de decremento diminui o valor inteiro em um | A-- dará 9 |
Operadores Relacionais
A tabela a seguir mostra todos os operadores relacionais suportados pela linguagem Objective-C. Assumir variávelA contém 10 e variável B contém 20, então -
Mostrar exemplos
Operador | Descrição | Exemplo |
---|---|---|
== | Verifica se os valores de dois operandos são iguais ou não; se sim, então a condição se torna verdadeira. | (A == B) não é verdade. |
! = | Verifica se os valores de dois operandos são iguais ou não; se os valores não forem iguais, a condição se torna verdadeira. | (A! = B) é verdade. |
> | Verifica se o valor do operando esquerdo é maior que o valor do operando direito; se sim, então a condição se torna verdadeira. | (A> B) não é verdade. |
< | Verifica se o valor do operando esquerdo é menor que o valor do operando direito; se sim, então a condição se torna verdadeira. | (A <B) é verdade. |
> = | Verifica se o valor do operando esquerdo é maior ou igual ao valor do operando direito; se sim, então a condição se torna verdadeira. | (A> = B) não é verdade. |
<= | Verifica se o valor do operando esquerdo é menor ou igual ao valor do operando direito; se sim, então a condição se torna verdadeira. | (A <= B) é verdadeiro. |
Operadores lógicos
A tabela a seguir mostra todos os operadores lógicos suportados pela linguagem Objective-C. Assumir variávelA detém 1 e variável B segura 0, então -
Mostrar exemplos
Operador | Descrição | Exemplo |
---|---|---|
&& | Operador lógico chamado AND. Se ambos os operandos forem diferentes de zero, a condição se torna verdadeira. | (A && B) é falso. |
|| | Operador lógico ou chamado. Se qualquer um dos dois operandos for diferente de zero, a condição se torna verdadeira. | (A || B) é verdade. |
! | Operador lógico chamado NOT. Use para reverter o estado lógico de seu operando. Se uma condição for verdadeira, o operador lógico NOT tornará falsa. | ! (A && B) é verdade. |
Operadores bit a bit
O operador bit a bit funciona em bits e executa a operação bit a bit. As tabelas de verdade para &, | e ^ são as seguintes -
p | q | p & q | p | q | p ^ q |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 |
Suponha que A = 60; e B = 13; agora em formato binário serão os seguintes -
A = 0011 1100
B = 0000 1101
-----------------
A&B = 0000 1100
A | B = 0011 1101
A ^ B = 0011 0001
~ A = 1100 0011
Os operadores bit a bit suportados pela linguagem Objective-C estão listados na tabela a seguir. Suponha que a variável A tenha 60 e a variável B tenha 13, então -
Mostrar exemplos
Operador | Descrição | Exemplo |
---|---|---|
E | O operador Binário AND copia um bit para o resultado se ele existir em ambos os operandos. | (A e B) dará 12, que é 0000 1100 |
| | O operador binário OR copia um bit se ele existir em qualquer operando. | (A | B) dará 61, que é 0011 1101 |
^ | O operador binário XOR copia o bit se estiver definido em um operando, mas não em ambos. | (A ^ B) dará 49, que é 0011 0001 |
~ | O operador de complemento binários é unário e tem o efeito de 'inverter' bits. | (~ A) dará -61, que é 1100 0011 na forma de complemento de 2. |
<< | Operador binário de deslocamento à esquerda. O valor dos operandos à esquerda é movido para a esquerda pelo número de bits especificado pelo operando à direita. | Um << 2 dará 240, que é 1111 0000 |
>> | Operador binário de deslocamento à direita. O valor dos operandos à esquerda é movido para a direita pelo número de bits especificado pelo operando à direita. | Um >> 2 dará 15, que é 0000 1111 |
Operadores de atribuição
Existem seguintes operadores de atribuição suportados pela linguagem Objective-C -
Mostrar exemplos
Operador | Descrição | Exemplo |
---|---|---|
= | Operador de atribuição simples, atribui valores de operandos do lado direito para operando do lado esquerdo | C = A + B irá atribuir o valor de A + B em C |
+ = | Adicionar operador de atribuição AND, adiciona o operando direito ao operando esquerdo e atribui o resultado ao operando esquerdo | C + = A é equivalente a C = C + A |
- = | Subtrai o operador de atribuição E, subtrai o operando direito do operando esquerdo e atribui o resultado ao operando esquerdo | C - = A é equivalente a C = C - A |
* = | Operador de atribuição Multiply AND, multiplica o operando direito pelo operando esquerdo e atribui o resultado ao operando esquerdo | C * = A é equivalente a C = C * A |
/ = | Operador de atribuição de divisão AND, divide o operando esquerdo com o operando direito e atribui o resultado ao operando esquerdo | C / = A é equivalente a C = C / A |
% = | Módulo E operador de atribuição, leva o módulo usando dois operandos e atribui o resultado ao operando esquerdo | C% = A é equivalente a C = C% A |
<< = | Deslocamento à esquerda E operador de atribuição | C << = 2 é igual a C = C << 2 |
>> = | Deslocamento à direita E operador de atribuição | C >> = 2 é igual a C = C >> 2 |
& = | Operador de atribuição AND bit a bit | C & = 2 é igual a C = C & 2 |
^ = | OR exclusivo bit a bit e operador de atribuição | C ^ = 2 é igual a C = C ^ 2 |
| = | OR inclusivo bit a bit e operador de atribuição | C | = 2 é igual a C = C | 2 |
Operadores diversos ↦ sizeof & ternário
Existem alguns outros operadores importantes, incluindo sizeof e ? : suportado pela linguagem Objective-C.
Mostrar exemplos
Operador | Descrição | Exemplo |
---|---|---|
tamanho de() | Retorna o tamanho de uma variável. | sizeof (a), onde a é inteiro, retornará 4. |
E | Retorna o endereço de uma variável. | &uma; fornecerá o endereço real da variável. |
* | Ponteiro para uma variável. | *uma; irá apontar para uma variável. |
? : | Expressão Condicional | Se a condição for verdadeira? Então valor X: Caso contrário, valor Y |
Precedência de operadores em Objective-C
A precedência do operador determina o agrupamento de termos em uma expressão. Isso afeta como uma expressão é avaliada. Certos operadores têm precedência mais alta do que outros; por exemplo, o operador de multiplicação tem precedência mais alta do que o operador de adição -
Por exemplo, x = 7 + 3 * 2; aqui, x é atribuído a 13, não 20, porque o operador * tem precedência mais alta do que +, portanto, primeiro é multiplicado por 3 * 2 e, em seguida, é adicionado a 7.
Aqui, os operadores com a precedência mais alta aparecem na parte superior da tabela, aqueles com a mais baixa aparecem na parte inferior. Em uma expressão, os operadores de precedência superior serão avaliados primeiro.
Categoria | Operador | Associatividade |
---|---|---|
Postfix | () [] ->. ++ - - | Da esquerda para direita |
Unário | + -! ~ ++ - - (tipo) * & sizeof | Direita para esquerda |
Multiplicativo | * /% | Da esquerda para direita |
Aditivo | + - | Da esquerda para direita |
Mudança | << >> | Da esquerda para direita |
Relacional | <<=>> = | Da esquerda para direita |
Igualdade | ==! = | Da esquerda para direita |
XOR bit a bit | ^ | Da esquerda para direita |
OR bit a bit | | | Da esquerda para direita |
E lógico | && | Da esquerda para direita |
OR lógico | || | Da esquerda para direita |
Condicional | ?: | Direita para esquerda |
Tarefa | = + = - = * = / =% = >> = << = & = ^ = | = | Direita para esquerda |
Vírgula | , | Da esquerda para direita |
Pode haver uma situação em que você precise executar um bloco de código várias vezes. Em geral, as instruções são executadas sequencialmente: a primeira instrução em uma função é executada primeiro, seguida pela segunda e assim por diante.
As linguagens de programação fornecem várias estruturas de controle que permitem caminhos de execução mais complicados.
Uma instrução de loop nos permite executar uma instrução ou grupo de instruções várias vezes e a seguir está a forma geral de uma instrução de loop na maioria das linguagens de programação -
A linguagem de programação Objective-C fornece os seguintes tipos de loop para lidar com os requisitos de loop. Clique nos links a seguir para verificar seus detalhes.
Sr. Não. | Tipo de Loop e Descrição |
---|---|
1 | loop while Repete uma declaração ou grupo de declarações enquanto uma determinada condição for verdadeira. Ele testa a condição antes de executar o corpo do loop. |
2 | para loop Execute uma sequência de instruções várias vezes e abrevia o código que gerencia a variável de loop. |
3 | fazer ... loop while Como uma instrução while, exceto que testa a condição no final do corpo do loop. |
4 | loops aninhados Você pode usar um ou mais loops dentro de qualquer outro loop while, for ou do..while. |
Declarações de controle de loop
As instruções de controle de loop alteram a execução de sua sequência normal. Quando a execução deixa um escopo, todos os objetos automáticos que foram criados nesse escopo são destruídos.
Objective-C suporta as seguintes instruções de controle. Clique nos links a seguir para verificar seus detalhes.
Sr. Não. | Declaração de controle e descrição |
---|---|
1 | declaração de quebra Termina o loop ou switch instrução e transfere a execução para a instrução imediatamente após o loop ou switch. |
2 | continuar declaração Faz com que o loop pule o restante de seu corpo e teste novamente sua condição imediatamente antes de reiterar. |
The Infinite Loop
Um loop se torna um loop infinito se uma condição nunca se torna falsa. oforloop é tradicionalmente usado para esse propósito. Como nenhuma das três expressões que formam o loop for é necessária, você pode fazer um loop infinito deixando a expressão condicional vazia.
#import <Foundation/Foundation.h>
int main () {
for( ; ; ) {
NSLog(@"This loop will run forever.\n");
}
return 0;
}
Quando a expressão condicional está ausente, ela é considerada verdadeira. Você pode ter uma expressão de inicialização e incremento, mas os programadores Objective-C mais comumente usam a construção for (;;) para significar um loop infinito.
As estruturas de tomada de decisão requerem que o programador especifique uma ou mais condições a serem avaliadas ou testadas pelo programa, junto com uma instrução ou instruções a serem executadas se a condição for determinada como verdadeira e, opcionalmente, outras instruções a serem executadas se a condição está determinado a ser falso.
A seguir está a forma geral de uma estrutura típica de tomada de decisão encontrada na maioria das linguagens de programação -
A linguagem de programação Objective-C assume qualquer non-zero e non-null valores como true, e se for zero ou null, então é assumido como false valor.
A linguagem de programação Objective-C fornece os seguintes tipos de declarações de tomada de decisão. Clique nos links a seguir para verificar seus detalhes -
Sr. Não. | Declaração e descrição |
---|---|
1 | declaração if A if statement consiste em uma expressão booleana seguida por uma ou mais instruções. |
2 | declaração if ... else A if statement pode ser seguido por um opcional else statement, que é executado quando a expressão booleana é falsa. |
3 | declarações if aninhadas Você pode usar um if ou else if declaração dentro de outra if ou else if afirmações). |
4 | declaração switch UMA switch instrução permite que uma variável seja testada quanto à igualdade em relação a uma lista de valores. |
5 | instruções switch aninhadas Você pode usar um switch declaração dentro de outra switch afirmações). |
O ? : Operador
Nós cobrimos conditional operator ? : no capítulo anterior, que pode ser usado para substituir if...elseafirmações. Tem a seguinte forma geral -
Exp1 ? Exp2 : Exp3;
Onde Exp1, Exp2 e Exp3 são expressões. Observe o uso e a localização do cólon.
O valor de um? expressão é determinada assim: Exp1 é avaliada. Se for verdade, então Exp2 é avaliado e se torna o valor de todo? expressão. Se Exp1 for falso, então Exp3 é avaliado e seu valor se torna o valor da expressão.
Uma função é um grupo de instruções que, juntas, executam uma tarefa. Cada programa Objective-C tem uma função C, que émain(), e todos os programas mais triviais podem definir funções adicionais.
Você pode dividir seu código em funções separadas. Como você divide seu código entre diferentes funções é com você, mas logicamente a divisão geralmente é para que cada função execute uma tarefa específica.
Uma função declarationinforma ao compilador o nome, o tipo de retorno e os parâmetros de uma função. Uma funçãodefinition fornece o corpo real da função.
Basicamente, em Objective-C, chamamos a função como método.
A estrutura de base Objective-C fornece vários métodos integrados que seu programa pode chamar. Por exemplo, métodoappendString() para anexar string a outra string.
Um método é conhecido com vários nomes, como uma função ou uma sub-rotina ou um procedimento, etc.
Definindo um Método
A forma geral de definição de método na linguagem de programação Objective-C é a seguinte -
- (return_type) method_name:( argumentType1 )argumentName1
joiningArgument2:( argumentType2 )argumentName2 ...
joiningArgumentn:( argumentTypen )argumentNamen {
body of the function
}
Uma definição de método na linguagem de programação Objective-C consiste em um cabeçalho de método e um corpo de método . Aqui estão todas as partes de um método -
Return Type- Um método pode retornar um valor. oreturn_typeé o tipo de dados do valor que a função retorna. Alguns métodos realizam as operações desejadas sem retornar um valor. Neste caso, o return_type é a palavra-chavevoid.
Method Name- Este é o nome real do método. O nome do método e a lista de parâmetros juntos constituem a assinatura do método.
Arguments- Um argumento é como um espaço reservado. Quando uma função é chamada, você passa um valor para o argumento. Esse valor é conhecido como parâmetro ou argumento real. A lista de parâmetros se refere ao tipo, ordem e número dos argumentos de um método. Os argumentos são opcionais; ou seja, um método não pode conter nenhum argumento.
Joining Argument - Um argumento de união é para torná-lo mais fácil de ler e deixar claro ao chamá-lo.
Method Body - O corpo do método contém uma coleção de instruções que definem o que o método faz.
Exemplo
A seguir está o código-fonte de um método chamado max(). Este método usa dois parâmetros num1 e num2 e retorna o máximo entre os dois -
/* function returning the max between two numbers */
- (int) max:(int) num1 secondNumber:(int) num2 {
/* local variable declaration */
int result;
if (num1 > num2) {
result = num1;
} else {
result = num2;
}
return result;
}
Declarações de método
Um método declarationinforma ao compilador sobre o nome de uma função e como chamar o método. O corpo real da função pode ser definido separadamente.
Uma declaração de método tem as seguintes partes -
- (return_type) function_name:( argumentType1 )argumentName1
joiningArgument2:( argumentType2 )argumentName2 ...
joiningArgumentn:( argumentTypen )argumentNamen;
Para a função max () definida acima, a seguir está a declaração do método -
-(int) max:(int)num1 andNum2:(int)num2;
A declaração do método é necessária quando você define um método em um arquivo de origem e chama esse método em outro arquivo. Nesse caso, você deve declarar a função na parte superior do arquivo que está chamando a função.
Chamando um método
Ao criar um método Objective-C, você dá uma definição do que a função deve fazer. Para usar um método, você terá que chamar essa função para executar a tarefa definida.
Quando um programa chama uma função, o controle do programa é transferido para o método chamado. Um método chamado executa uma tarefa definida e, quando sua instrução de retorno é executada ou quando sua chave de fechamento de finalização de função é atingida, ele retorna o controle do programa ao programa principal.
Para chamar um método, você simplesmente precisa passar os parâmetros necessários junto com o nome do método e, se o método retornar um valor, você pode armazenar o valor retornado. Por exemplo -
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
/* method declaration */
- (int)max:(int)num1 andNum2:(int)num2;
@end
@implementation SampleClass
/* method returning the max between two numbers */
- (int)max:(int)num1 andNum2:(int)num2 {
/* local variable declaration */
int result;
if (num1 > num2) {
result = num1;
} else {
result = num2;
}
return result;
}
@end
int main () {
/* local variable definition */
int a = 100;
int b = 200;
int ret;
SampleClass *sampleClass = [[SampleClass alloc]init];
/* calling a method to get max value */
ret = [sampleClass max:a andNum2:b];
NSLog(@"Max value is : %d\n", ret );
return 0;
}
Eu mantive a função max () junto com a função main () e cumpri o código-fonte. Durante a execução do executável final, ele produziria o seguinte resultado -
2013-09-07 22:28:45.912 demo[26080] Max value is : 200
Argumentos de função
Se uma função deve usar argumentos, ela deve declarar variáveis que aceitam os valores dos argumentos. Essas variáveis são chamadas deformal parameters da função.
Os parâmetros formais se comportam como outras variáveis locais dentro da função e são criados na entrada na função e destruídos na saída.
Ao chamar uma função, existem duas maneiras de os argumentos serem passados para uma função -
Sr. Não. | Tipo e descrição da chamada |
---|---|
1 | Chamada por valor Este método copia o valor real de um argumento para o parâmetro formal da função. Nesse caso, as alterações feitas no parâmetro dentro da função não têm efeito no argumento. |
2 | Chamada por referência Este método copia o endereço de um argumento no parâmetro formal. Dentro da função, o endereço é usado para acessar o argumento real usado na chamada. Isso significa que as alterações feitas no parâmetro afetam o argumento. |
Por padrão, Objective-C usa call by valuepara passar argumentos. Em geral, isso significa que o código dentro de uma função não pode alterar os argumentos usados para chamar a função e o exemplo mencionado acima ao chamar a função max () usou o mesmo método.
Uma classe Objective-C define um objeto que combina dados com comportamento relacionado. Às vezes, faz sentido representar apenas uma única tarefa ou unidade de comportamento, em vez de uma coleção de métodos.
Os blocos são um recurso de nível de linguagem adicionado a C, Objective-C e C ++ que permitem criar segmentos distintos de código que podem ser passados para métodos ou funções como se fossem valores. Blocos são objetos Objective-C, o que significa que podem ser adicionados a coleções como NSArray ou NSDictionary. Eles também têm a capacidade de capturar valores do escopo envolvente, tornando-os semelhantes a fechamentos ou lambdas em outras linguagens de programação
Sintaxe de declaração de bloco simples
returntype (^blockName)(argumentType);
Implementação de bloco simples
returntype (^blockName)(argumentType)= ^{
};
Aqui está um exemplo simples
void (^simpleBlock)(void) = ^{
NSLog(@"This is a block");
};
Podemos invocar o bloco usando
simpleBlock();
Blocos recebem argumentos e valores de retorno
Os blocos também podem receber argumentos e valores de retorno, assim como métodos e funções.
Aqui está um exemplo simples para implementar e invocar um bloco com argumentos e valores de retorno.
double (^multiplyTwoValues)(double, double) =
^(double firstValue, double secondValue) {
return firstValue * secondValue;
};
double result = multiplyTwoValues(2,4);
NSLog(@"The result is %f", result);
Blocos usando definições de tipo
Aqui está um exemplo simples usando typedef em bloco. Observe este exemplodoesn't work no online compilerpor enquanto. UsarXCode para executar o mesmo.
#import <Foundation/Foundation.h>
typedef void (^CompletionBlock)();
@interface SampleClass:NSObject
- (void)performActionWithCompletion:(CompletionBlock)completionBlock;
@end
@implementation SampleClass
- (void)performActionWithCompletion:(CompletionBlock)completionBlock {
NSLog(@"Action Performed");
completionBlock();
}
@end
int main() {
/* my first program in Objective-C */
SampleClass *sampleClass = [[SampleClass alloc]init];
[sampleClass performActionWithCompletion:^{
NSLog(@"Completion is called to intimate action is performed.");
}];
return 0;
}
Vamos compilá-lo e executá-lo, ele produzirá o seguinte resultado -
2013-09-10 08:13:57.155 demo[284:303] Action Performed
2013-09-10 08:13:57.157 demo[284:303] Completion is called to intimate action is performed.
Blocos são mais usados em aplicativos iOS e Mac OS X. Portanto, é mais importante entender o uso de blocos.
Na linguagem de programação Objective-C, a fim de salvar os tipos de dados básicos como int, float, bool na forma de objeto,
Objective-C fornece uma variedade de métodos para trabalhar com NSNumber e os mais importantes estão listados na tabela a seguir.
Sr. Não. | Método e Descrição |
---|---|
1 | + (NSNumber *)numberWithBool:(BOOL)value Cria e retorna um objeto NSNumber contendo um determinado valor, tratando-o como um BOOL. |
2 | + (NSNumber *)numberWithChar:(char)value Cria e retorna um objeto NSNumber contendo um determinado valor, tratando-o como um caractere assinado. |
3 | + (NSNumber *)numberWithDouble:(double)value Cria e retorna um objeto NSNumber contendo um determinado valor, tratando-o como um duplo. |
4 | + (NSNumber *)numberWithFloat:(float)value Cria e retorna um objeto NSNumber contendo um determinado valor, tratando-o como um float. |
5 | + (NSNumber *)numberWithInt:(int)value Cria e retorna um objeto NSNumber contendo um determinado valor, tratando-o como um int assinado. |
6 | + (NSNumber *)numberWithInteger:(NSInteger)value Cria e retorna um objeto NSNumber contendo um determinado valor, tratando-o como um NSInteger. |
7 | - (BOOL)boolValue Retorna o valor do receptor como um BOOL. |
8 | - (char)charValue Retorna o valor do receptor como um char. |
9 | - (double)doubleValue Retorna o valor do receptor como um duplo. |
10 | - (float)floatValue Retorna o valor do receptor como um float. |
11 | - (NSInteger)integerValue Retorna o valor do receptor como um NSInteger. |
12 | - (int)intValue Retorna o valor do receptor como um int. |
13 | - (NSString *)stringValue Retorna o valor do receptor como uma string legível por humanos. |
Aqui está um exemplo simples de uso de NSNumber que multiplica dois números e retorna o produto.
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
- (NSNumber *)multiplyA:(NSNumber *)a withB:(NSNumber *)b;
@end
@implementation SampleClass
- (NSNumber *)multiplyA:(NSNumber *)a withB:(NSNumber *)b {
float number1 = [a floatValue];
float number2 = [b floatValue];
float product = number1 * number2;
NSNumber *result = [NSNumber numberWithFloat:product];
return result;
}
@end
int main() {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
SampleClass *sampleClass = [[SampleClass alloc]init];
NSNumber *a = [NSNumber numberWithFloat:10.5];
NSNumber *b = [NSNumber numberWithFloat:10.0];
NSNumber *result = [sampleClass multiplyA:a withB:b];
NSString *resultString = [result stringValue];
NSLog(@"The product is %@",resultString);
[pool drain];
return 0;
}
Agora, quando compilarmos e executarmos o programa, obteremos o seguinte resultado.
2013-09-14 18:53:40.575 demo[16787] The product is 105
A linguagem de programação Objective-C fornece uma estrutura de dados chamada the array, que pode armazenar uma coleção sequencial de tamanho fixo de elementos do mesmo tipo. Uma matriz é usada para armazenar uma coleção de dados, mas geralmente é mais útil pensar em uma matriz como uma coleção de variáveis do mesmo tipo.
Em vez de declarar variáveis individuais, como número0, número1, ... e número99, você declara uma variável de matriz, como números e usa números [0], números [1] e ..., números [99] para representar variáveis individuais. Um elemento específico em uma matriz é acessado por um índice.
Todos os arrays consistem em locais de memória contíguos. O endereço mais baixo corresponde ao primeiro elemento e o endereço mais alto ao último elemento.
Declaração de matrizes
Para declarar uma matriz em Objective-C, um programador especifica o tipo dos elementos e o número de elementos exigidos por uma matriz da seguinte maneira -
type arrayName [ arraySize ];
Isso é chamado de matriz unidimensional . oarraySize deve ser uma constante inteira maior que zero e typepode ser qualquer tipo de dados Objective-C válido. Por exemplo, para declarar uma matriz de 10 elementos chamadabalance do tipo double, use esta instrução -
double balance[10];
Agora, balance é uma matriz variável, que é suficiente para conter até 10 números duplos.
Inicializando matrizes
Você pode inicializar um array em Objective-C um por um ou usando uma única instrução da seguinte maneira -
double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
O número de valores entre colchetes {} não pode ser maior do que o número de elementos que declaramos para a matriz entre colchetes []. A seguir está um exemplo para atribuir um único elemento da matriz -
Se você omitir o tamanho do array, um array grande o suficiente para conter a inicialização é criado. Portanto, se você escrever -
double balance[] = {1000.0, 2.0, 3.4, 17.0, 50.0};
Você criará exatamente a mesma matriz que fez no exemplo anterior.
balance[4] = 50.0;
A instrução acima atribui ao elemento número 5 na matriz um valor de 50,0. O array com o 4º índice será o 5º, ou seja, o último elemento, porque todos os arrays têm 0 como o índice do primeiro elemento, também chamado de índice base. A seguir está a representação pictórica da mesma matriz que discutimos acima -
Acessando Elementos de Matriz
Um elemento é acessado indexando o nome da matriz. Isso é feito colocando o índice do elemento entre colchetes após o nome da matriz. Por exemplo -
double salary = balance[9];
A instrução acima pegará o 10º elemento da matriz e atribuirá o valor à variável salary. A seguir está um exemplo, que usará todos os três conceitos acima mencionados viz. declaração, atribuição e acesso a matrizes -
#import <Foundation/Foundation.h>
int main () {
int n[ 10 ]; /* n is an array of 10 integers */
int i,j;
/* initialize elements of array n to 0 */
for ( i = 0; i < 10; i++ ) {
n[ i ] = i + 100; /* set element at location i to i + 100 */
}
/* output each array element's value */
for (j = 0; j < 10; j++ ) {
NSLog(@"Element[%d] = %d\n", j, n[j] );
}
return 0;
}
Quando o código acima é compilado e executado, ele produz o seguinte resultado -
2013-09-14 01:24:06.669 demo[16508] Element[0] = 100
2013-09-14 01:24:06.669 demo[16508] Element[1] = 101
2013-09-14 01:24:06.669 demo[16508] Element[2] = 102
2013-09-14 01:24:06.669 demo[16508] Element[3] = 103
2013-09-14 01:24:06.669 demo[16508] Element[4] = 104
2013-09-14 01:24:06.669 demo[16508] Element[5] = 105
2013-09-14 01:24:06.669 demo[16508] Element[6] = 106
2013-09-14 01:24:06.669 demo[16508] Element[7] = 107
2013-09-14 01:24:06.669 demo[16508] Element[8] = 108
2013-09-14 01:24:06.669 demo[16508] Element[9] = 109
Arrays Objective-C em detalhes
Arrays são importantes para Objective-C e precisam de muitos mais detalhes. Seguem alguns conceitos importantes relacionados a array que devem ser claros para um programador Objective-C -
Sr. Não. | Conceito e descrição |
---|---|
1 | Matrizes multidimensionais Objective-C suporta arrays multidimensionais. A forma mais simples da matriz multidimensional é a matriz bidimensional. |
2 | Passando matrizes para funções Você pode passar para a função um ponteiro para uma matriz, especificando o nome da matriz sem um índice. |
3 | Retorna a matriz de uma função Objective-C permite que uma função retorne um array. |
4 | Ponteiro para uma matriz Você pode gerar um ponteiro para o primeiro elemento de uma matriz simplesmente especificando o nome da matriz, sem nenhum índice. |
Os ponteiros em Objective-C são fáceis e divertidos de aprender. Algumas tarefas de programação Objective-C são realizadas mais facilmente com ponteiros, e outras tarefas, como alocação de memória dinâmica, não podem ser executadas sem o uso de ponteiros. Portanto, torna-se necessário aprender ponteiros para se tornar um programador Objective-C perfeito. Vamos começar a aprendê-los em etapas simples e fáceis.
Como você sabe, cada variável é um local da memória e cada local da memória tem seu endereço definido, que pode ser acessado usando o operador E comercial (&), que denota um endereço na memória. Considere o seguinte exemplo, que imprimirá o endereço das variáveis definidas -
#import <Foundation/Foundation.h>
int main () {
int var1;
char var2[10];
NSLog(@"Address of var1 variable: %x\n", &var1 );
NSLog(@"Address of var2 variable: %x\n", &var2 );
return 0;
}
Quando o código acima é compilado e executado, ele produz o resultado algo como a seguir -
2013-09-13 03:18:45.727 demo[17552] Address of var1 variable: 1c0843fc
2013-09-13 03:18:45.728 demo[17552] Address of var2 variable: 1c0843f0
Então, você entendeu o que é endereço de memória e como acessá-lo, então a base do conceito acabou. Agora vamos ver o que é um ponteiro.
O que são ponteiros?
UMA pointeré uma variável cujo valor é o endereço de outra variável, ou seja, o endereço direto do local da memória. Como qualquer variável ou constante, você deve declarar um ponteiro antes de usá-lo para armazenar qualquer endereço de variável. A forma geral de uma declaração de variável de ponteiro é -
type *var-name;
Aqui, typeé o tipo base do ponteiro; deve ser um tipo de dados Objective-C válido evar-nameé o nome da variável de ponteiro. O asterisco * que você usou para declarar um ponteiro é o mesmo asterisco que você usa para a multiplicação. No entanto, nesta declaração, o asterisco está sendo usado para designar uma variável como um ponteiro. A seguir estão as declarações de ponteiro válidas -
int *ip; /* pointer to an integer */
double *dp; /* pointer to a double */
float *fp; /* pointer to a float */
char *ch /* pointer to a character */
O tipo de dados real do valor de todos os ponteiros, seja inteiro, flutuante, caractere ou outro, é o mesmo, um número hexadecimal longo que representa um endereço de memória. A única diferença entre ponteiros de diferentes tipos de dados é o tipo de dados da variável ou constante para a qual o ponteiro aponta.
Como usar ponteiros?
Existem algumas operações importantes, que faremos com a ajuda de ponteiros com muita freqüência. (a) definimos uma variável de ponteiro, (b) atribuir o endereço de uma variável a um ponteiro, e (c)finalmente acesse o valor no endereço disponível na variável de ponteiro. Isso é feito usando o operador unário*que retorna o valor da variável localizada no endereço especificado por seu operando. O exemplo a seguir faz uso dessas operações -
#import <Foundation/Foundation.h>
int main () {
int var = 20; /* actual variable declaration */
int *ip; /* pointer variable declaration */
ip = &var; /* store address of var in pointer variable*/
NSLog(@"Address of var variable: %x\n", &var );
/* address stored in pointer variable */
NSLog(@"Address stored in ip variable: %x\n", ip );
/* access the value using the pointer */
NSLog(@"Value of *ip variable: %d\n", *ip );
return 0;
}
Quando o código acima é compilado e executado, ele produz o resultado algo como a seguir -
2013-09-13 03:20:21.873 demo[24179] Address of var variable: 337ed41c
2013-09-13 03:20:21.873 demo[24179] Address stored in ip variable: 337ed41c
2013-09-13 03:20:21.874 demo[24179] Value of *ip variable: 20
Ponteiros NULL em Objective-C
É sempre uma boa prática atribuir um valor NULL a uma variável de ponteiro, caso você não tenha um endereço exato a ser atribuído. Isso é feito no momento da declaração da variável. Um ponteiro que é atribuído NULL é chamado denull ponteiro.
O ponteiro NULL é uma constante com valor zero definido em várias bibliotecas padrão. Considere o seguinte programa -
#import <Foundation/Foundation.h>
int main () {
int *ptr = NULL;
NSLog(@"The value of ptr is : %x\n", ptr );
return 0;
}
Quando o código acima é compilado e executado, ele produz o seguinte resultado -
2013-09-13 03:21:19.447 demo[28027] The value of ptr is : 0
Na maioria dos sistemas operacionais, os programas não têm permissão para acessar a memória no endereço 0 porque essa memória é reservada pelo sistema operacional. No entanto, o endereço de memória 0 tem um significado especial; ele sinaliza que o ponteiro não se destina a apontar para um local de memória acessível. Mas, por convenção, se um ponteiro contém o valor nulo (zero), ele não aponta para nada.
Para verificar se há um ponteiro nulo, você pode usar uma instrução if da seguinte maneira -
if(ptr) /* succeeds if p is not null */
if(!ptr) /* succeeds if p is null */
Ponteiros Objective-C em detalhes
Os ponteiros têm muitos conceitos fáceis e são muito importantes para a programação Objective-C. Seguem alguns conceitos importantes de ponteiro, que devem ser claros para um programador Objective-C -
Sr. Não. | Conceito e descrição |
---|---|
1 | Objective-C - Aritmética de ponteiro Existem quatro operadores aritméticos que podem ser usados em ponteiros: ++, -, +, - |
2 | Objective-C - Matriz de ponteiros Você pode definir matrizes para conter uma série de ponteiros. |
3 | Objective-C - Ponteiro a ponteiro Objective-C permite que você tenha um ponteiro sobre um ponteiro e assim por diante. |
4 | Passando ponteiros para funções em Objective-C Passar um argumento por referência ou por endereço permite que o argumento passado seja alterado na função de chamada pela função chamada. |
5 | Ponteiro de retorno de funções em Objective-C Objective-C permite que uma função retorne um ponteiro para uma variável local, variável estática e memória alocada dinamicamente. |
A string na linguagem de programação Objective-C é representada usando NSString e sua subclasse NSMutableString fornece várias maneiras de criar objetos string. A maneira mais simples de criar um objeto string é usar a construção Objective-C @ "..." -
NSString *greeting = @"Hello";
Um exemplo simples para criar e imprimir uma string é mostrado abaixo.
#import <Foundation/Foundation.h>
int main () {
NSString *greeting = @"Hello";
NSLog(@"Greeting message: %@\n", greeting );
return 0;
}
Quando o código acima é compilado e executado, ele produz um resultado como o seguinte -
2013-09-11 01:21:39.922 demo[23926] Greeting message: Hello
Objective-C suporta uma ampla gama de métodos para manipular strings -
Sr. Não. | Método e Objetivo |
---|---|
1 | - (NSString *)capitalizedString; Retorna uma representação em maiúscula do receptor. |
2 | - (unichar)characterAtIndex:(NSUInteger)index; Retorna o caractere em uma determinada posição da matriz. |
3 | - (double)doubleValue; Retorna o valor de ponto flutuante do texto do receptor como um duplo. |
4 | - (float)floatValue; Retorna o valor de ponto flutuante do texto do receptor como um float. |
5 | - (BOOL)hasPrefix:(NSString *)aString; Retorna um valor booleano que indica se uma determinada string corresponde aos caracteres iniciais do receptor. |
6 | - (BOOL)hasSuffix:(NSString *)aString; Retorna um valor booleano que indica se uma determinada string corresponde aos caracteres finais do receptor. |
7 | - (id)initWithFormat:(NSString *)format ...; Retorna um objeto NSString inicializado usando uma determinada string de formato como um modelo no qual os valores de argumento restantes são substituídos. |
8 | - (NSInteger)integerValue; Retorna o valor NSInteger do texto do receptor. |
9 | - (BOOL)isEqualToString:(NSString *)aString; Retorna um valor booleano que indica se uma determinada string é igual ao receptor usando uma comparação literal baseada em Unicode. |
10 | - (NSUInteger)length; Retorna o número de caracteres Unicode no receptor. |
11 | - (NSString *)lowercaseString; Retorna a representação em minúsculas do receptor. |
12 | - (NSRange)rangeOfString:(NSString *)aString; Encontra e retorna o intervalo da primeira ocorrência de uma determinada string dentro do receptor. |
13 | - (NSString *)stringByAppendingFormat:(NSString *)format ...; Retorna uma string feita anexando ao receptor uma string construída a partir de uma string de formato fornecida e os seguintes argumentos. |
14 | - (NSString *)stringByTrimmingCharactersInSet:(NSCharacterSet *)set; Retorna uma nova string feita pela remoção de ambas as extremidades dos caracteres do receptor contidos em um determinado conjunto de caracteres. |
15 | - (NSString *)substringFromIndex:(NSUInteger)anIndex; Retorna uma nova string contendo os caracteres do receptor, desde aquele em um determinado índice até o final. |
O exemplo a seguir usa algumas das funções mencionadas acima -
#import <Foundation/Foundation.h>
int main () {
NSString *str1 = @"Hello";
NSString *str2 = @"World";
NSString *str3;
int len ;
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
/* uppercase string */
str3 = [str2 uppercaseString];
NSLog(@"Uppercase String : %@\n", str3 );
/* concatenates str1 and str2 */
str3 = [str1 stringByAppendingFormat:@"World"];
NSLog(@"Concatenated string: %@\n", str3 );
/* total length of str3 after concatenation */
len = [str3 length];
NSLog(@"Length of Str3 : %d\n", len );
/* InitWithFormat */
str3 = [[NSString alloc] initWithFormat:@"%@ %@",str1,str2];
NSLog(@"Using initWithFormat: %@\n", str3 );
[pool drain];
return 0;
}
Quando o código acima é compilado e executado, ele produz um resultado como o seguinte -
2013-09-11 01:15:45.069 demo[30378] Uppercase String : WORLD
2013-09-11 01:15:45.070 demo[30378] Concatenated string: HelloWorld
2013-09-11 01:15:45.070 demo[30378] Length of Str3 : 10
2013-09-11 01:15:45.070 demo[30378] Using initWithFormat: Hello World
Você pode encontrar uma lista completa de métodos relacionados a Objective-C NSString em NSString Class Reference.
Os arrays Objective-C permitem definir o tipo de variáveis que podem conter vários itens de dados do mesmo tipo, mas structure é outro tipo de dados definido pelo usuário disponível na programação Objective-C que permite combinar itens de dados de diferentes tipos.
As estruturas são usadas para representar um registro. Suponha que você deseja manter o controle de seus livros em uma biblioteca. Você pode querer rastrear os seguintes atributos sobre cada livro -
- Title
- Author
- Subject
- ID do livro
Definindo uma Estrutura
Para definir uma estrutura, você deve usar o structdeclaração. A instrução struct define um novo tipo de dados, com mais de um membro para seu programa. O formato da instrução de estrutura é este -
struct [structure tag] {
member definition;
member definition;
...
member definition;
} [one or more structure variables];
o structure tagé opcional e cada definição de membro é uma definição de variável normal, como int i; ou flutuar f; ou qualquer outra definição de variável válida. No final da definição da estrutura, antes do ponto e vírgula final, você pode especificar uma ou mais variáveis de estrutura, mas é opcional. Esta é a maneira como você declararia a estrutura do livro -
struct Books {
NSString *title;
NSString *author;
NSString *subject;
int book_id;
} book;
Acessando membros da estrutura
Para acessar qualquer membro de uma estrutura, usamos o member access operator (.). O operador de acesso de membro é codificado como um período entre o nome da variável de estrutura e o membro da estrutura que desejamos acessar. Você usariastructpalavra-chave para definir variáveis do tipo de estrutura. A seguir está o exemplo para explicar o uso da estrutura -
#import <Foundation/Foundation.h>
struct Books {
NSString *title;
NSString *author;
NSString *subject;
int book_id;
};
int main() {
struct Books Book1; /* Declare Book1 of type Book */
struct Books Book2; /* Declare Book2 of type Book */
/* book 1 specification */
Book1.title = @"Objective-C Programming";
Book1.author = @"Nuha Ali";
Book1.subject = @"Objective-C Programming Tutorial";
Book1.book_id = 6495407;
/* book 2 specification */
Book2.title = @"Telecom Billing";
Book2.author = @"Zara Ali";
Book2.subject = @"Telecom Billing Tutorial";
Book2.book_id = 6495700;
/* print Book1 info */
NSLog(@"Book 1 title : %@\n", Book1.title);
NSLog(@"Book 1 author : %@\n", Book1.author);
NSLog(@"Book 1 subject : %@\n", Book1.subject);
NSLog(@"Book 1 book_id : %d\n", Book1.book_id);
/* print Book2 info */
NSLog(@"Book 2 title : %@\n", Book2.title);
NSLog(@"Book 2 author : %@\n", Book2.author);
NSLog(@"Book 2 subject : %@\n", Book2.subject);
NSLog(@"Book 2 book_id : %d\n", Book2.book_id);
return 0;
}
Quando o código acima é compilado e executado, ele produz o seguinte resultado -
2013-09-14 04:20:07.947 demo[20591] Book 1 title : Objective-C Programming
2013-09-14 04:20:07.947 demo[20591] Book 1 author : Nuha Ali
2013-09-14 04:20:07.947 demo[20591] Book 1 subject : Objective-C Programming Tutorial
2013-09-14 04:20:07.947 demo[20591] Book 1 book_id : 6495407
2013-09-14 04:20:07.947 demo[20591] Book 2 title : Telecom Billing
2013-09-14 04:20:07.947 demo[20591] Book 2 author : Zara Ali
2013-09-14 04:20:07.947 demo[20591] Book 2 subject : Telecom Billing Tutorial
2013-09-14 04:20:07.947 demo[20591] Book 2 book_id : 6495700
Estruturas como argumentos de função
Você pode passar uma estrutura como um argumento de função de maneira muito semelhante à que passa qualquer outra variável ou ponteiro. Você acessaria as variáveis de estrutura da mesma forma que acessou no exemplo acima -
#import <Foundation/Foundation.h>
struct Books {
NSString *title;
NSString *author;
NSString *subject;
int book_id;
};
@interface SampleClass:NSObject
/* function declaration */
- (void) printBook:( struct Books) book ;
@end
@implementation SampleClass
- (void) printBook:( struct Books) book {
NSLog(@"Book title : %@\n", book.title);
NSLog(@"Book author : %@\n", book.author);
NSLog(@"Book subject : %@\n", book.subject);
NSLog(@"Book book_id : %d\n", book.book_id);
}
@end
int main() {
struct Books Book1; /* Declare Book1 of type Book */
struct Books Book2; /* Declare Book2 of type Book */
/* book 1 specification */
Book1.title = @"Objective-C Programming";
Book1.author = @"Nuha Ali";
Book1.subject = @"Objective-C Programming Tutorial";
Book1.book_id = 6495407;
/* book 2 specification */
Book2.title = @"Telecom Billing";
Book2.author = @"Zara Ali";
Book2.subject = @"Telecom Billing Tutorial";
Book2.book_id = 6495700;
SampleClass *sampleClass = [[SampleClass alloc]init];
/* print Book1 info */
[sampleClass printBook: Book1];
/* Print Book2 info */
[sampleClass printBook: Book2];
return 0;
}
Quando o código acima é compilado e executado, ele produz o seguinte resultado -
2013-09-14 04:34:45.725 demo[8060] Book title : Objective-C Programming
2013-09-14 04:34:45.725 demo[8060] Book author : Nuha Ali
2013-09-14 04:34:45.725 demo[8060] Book subject : Objective-C Programming Tutorial
2013-09-14 04:34:45.725 demo[8060] Book book_id : 6495407
2013-09-14 04:34:45.725 demo[8060] Book title : Telecom Billing
2013-09-14 04:34:45.725 demo[8060] Book author : Zara Ali
2013-09-14 04:34:45.725 demo[8060] Book subject : Telecom Billing Tutorial
2013-09-14 04:34:45.725 demo[8060] Book book_id : 6495700
Indicadores para estruturas
Você pode definir ponteiros para estruturas de maneira muito semelhante à medida que define ponteiros para qualquer outra variável da seguinte maneira -
struct Books *struct_pointer;
Agora, você pode armazenar o endereço de uma variável de estrutura na variável de ponteiro definida acima. Para encontrar o endereço de uma variável de estrutura, coloque o operador & antes do nome da estrutura da seguinte maneira -
struct_pointer = &Book1;
Para acessar os membros de uma estrutura usando um ponteiro para essa estrutura, você deve usar o operador -> da seguinte maneira -
struct_pointer->title;
Vamos reescrever o exemplo acima usando o ponteiro de estrutura, espero que seja fácil para você entender o conceito -
#import <Foundation/Foundation.h>
struct Books {
NSString *title;
NSString *author;
NSString *subject;
int book_id;
};
@interface SampleClass:NSObject
/* function declaration */
- (void) printBook:( struct Books *) book ;
@end
@implementation SampleClass
- (void) printBook:( struct Books *) book {
NSLog(@"Book title : %@\n", book->title);
NSLog(@"Book author : %@\n", book->author);
NSLog(@"Book subject : %@\n", book->subject);
NSLog(@"Book book_id : %d\n", book->book_id);
}
@end
int main() {
struct Books Book1; /* Declare Book1 of type Book */
struct Books Book2; /* Declare Book2 of type Book */
/* book 1 specification */
Book1.title = @"Objective-C Programming";
Book1.author = @"Nuha Ali";
Book1.subject = @"Objective-C Programming Tutorial";
Book1.book_id = 6495407;
/* book 2 specification */
Book2.title = @"Telecom Billing";
Book2.author = @"Zara Ali";
Book2.subject = @"Telecom Billing Tutorial";
Book2.book_id = 6495700;
SampleClass *sampleClass = [[SampleClass alloc]init];
/* print Book1 info by passing address of Book1 */
[sampleClass printBook:&Book1];
/* print Book2 info by passing address of Book2 */
[sampleClass printBook:&Book2];
return 0;
}
Quando o código acima é compilado e executado, ele produz o seguinte resultado -
2013-09-14 04:38:13.942 demo[20745] Book title : Objective-C Programming
2013-09-14 04:38:13.942 demo[20745] Book author : Nuha Ali
2013-09-14 04:38:13.942 demo[20745] Book subject : Objective-C Programming Tutorial
2013-09-14 04:38:13.942 demo[20745] Book book_id : 6495407
2013-09-14 04:38:13.942 demo[20745] Book title : Telecom Billing
2013-09-14 04:38:13.942 demo[20745] Book author : Zara Ali
2013-09-14 04:38:13.942 demo[20745] Book subject : Telecom Billing Tutorial
2013-09-14 04:38:13.942 demo[20745] Book book_id : 6495700
Campos de bits
Os campos de bits permitem o empacotamento de dados em uma estrutura. Isso é especialmente útil quando a memória ou o armazenamento de dados são escassos. Exemplos típicos -
Empacotando vários objetos em uma palavra de máquina. por exemplo, sinalizadores de 1 bit podem ser compactados.
Leitura de formatos de arquivo externos - formatos de arquivo não padrão podem ser lidos. Por exemplo, inteiros de 9 bits.
Objective-C nos permite fazer isso em uma definição de estrutura, colocando: comprimento de bit após a variável. Por exemplo -
struct packed_struct {
unsigned int f1:1;
unsigned int f2:1;
unsigned int f3:1;
unsigned int f4:1;
unsigned int type:4;
unsigned int my_int:9;
} pack;
Aqui, o pack_struct contém 6 membros: Quatro sinalizadores de 1 bit f1..f3, um tipo de 4 bits e um my_int de 9 bits.
Objective-C compacta automaticamente os campos de bits acima da forma mais compacta possível, desde que o comprimento máximo do campo seja menor ou igual ao comprimento da palavra inteira do computador. Se este não for o caso, alguns compiladores podem permitir a sobreposição de memória para os campos, enquanto outros armazenariam o próximo campo na próxima palavra.
o Objective-C Preprocessornão faz parte do compilador, mas é uma etapa separada no processo de compilação. Em termos simplistas, um pré-processador Objective-C é apenas uma ferramenta de substituição de texto e instrui o compilador a fazer o pré-processamento necessário antes da compilação real. Vamos nos referir ao Pré-processador Objective-C como OCPP.
Todos os comandos do pré-processador começam com um símbolo de cerquilha (#). Deve ser o primeiro caractere não vazio e, para facilitar a leitura, uma diretiva do pré-processador deve começar na primeira coluna. A seção a seguir lista todas as diretivas importantes do pré-processador -
Sr. Não. | Diretriz e descrição |
---|---|
1 | #define Substitui uma macro de pré-processador |
2 | #include Insere um cabeçalho específico de outro arquivo |
3 | #undef Cancela a definição de uma macro de pré-processador |
4 | #ifdef Retorna verdadeiro se esta macro estiver definida |
5 | #ifndef Retorna verdadeiro se esta macro não estiver definida |
6 | #if Testa se uma condição de tempo de compilação é verdadeira |
7 | #else A alternativa para #if |
8 | #elif #else an #if em uma declaração |
9 | #endif Ends preprocessor conditional |
10 | #error Prints error message on stderr |
11 | #pragma Issues special commands to the compiler using a standardized method |
Preprocessors Examples
Analyze the following examples to understand various directives.
#define MAX_ARRAY_LENGTH 20
This directive tells the OCPP to replace instances of MAX_ARRAY_LENGTH with 20. Use #define for constants to increase readability.
#import <Foundation/Foundation.h>
#include "myheader.h"
These directives tell the OCPP to get foundation.h from Foundation Framework and add the text to the current source file. The next line tells OCPP to get myheader.h from the local directory and add the content to the current source file.
#undef FILE_SIZE
#define FILE_SIZE 42
This tells the OCPP to undefine existing FILE_SIZE and define it as 42.
#ifndef MESSAGE
#define MESSAGE "You wish!"
#endif
This tells the OCPP to define MESSAGE only if MESSAGE isn't already defined.
#ifdef DEBUG
/* Your debugging statements here */
#endif
This tells the OCPP to do the process the statements enclosed if DEBUG is defined. This is useful if you pass the -DDEBUG flag to gcc compiler at the time of compilation. This will define DEBUG, so you can turn debugging on and off on the fly during compilation.
Predefined Macros
ANSI C defines a number of macros. Although each one is available for your use in programming, the predefined macros should not be directly modified.
Sr.No. | Macro & Description |
---|---|
1 | __DATE__ The current date as a character literal in "MMM DD YYYY" format |
2 | __TIME__ The current time as a character literal in "HH:MM:SS" format |
3 | __FILE__ This contains the current filename as a string literal. |
4 | __LINE__ This contains the current line number as a decimal constant. |
5 | __STDC__ Defined as 1 when the compiler complies with the ANSI standard. |
Let's try the following example −
#import <Foundation/Foundation.h>
int main() {
NSLog(@"File :%s\n", __FILE__ );
NSLog(@"Date :%s\n", __DATE__ );
NSLog(@"Time :%s\n", __TIME__ );
NSLog(@"Line :%d\n", __LINE__ );
NSLog(@"ANSI :%d\n", __STDC__ );
return 0;
}
When the above code in a file main.m is compiled and executed, it produces the following result −
2013-09-14 04:46:14.859 demo[20683] File :main.m
2013-09-14 04:46:14.859 demo[20683] Date :Sep 14 2013
2013-09-14 04:46:14.859 demo[20683] Time :04:46:14
2013-09-14 04:46:14.859 demo[20683] Line :8
2013-09-14 04:46:14.859 demo[20683] ANSI :1
Preprocessor Operators
The Objective-C preprocessor offers following operators to help you in creating macros −
Macro Continuation (\)
A macro usually must be contained on a single line. The macro continuation operator is used to continue a macro that is too long for a single line. For example −
#define message_for(a, b) \
NSLog(@#a " and " #b ": We love you!\n")
Stringize (#)
The stringize or number-sign operator ('#'), when used within a macro definition, converts a macro parameter into a string constant. This operator may be used only in a macro that has a specified argument or parameter list. For example −
#import <Foundation/Foundation.h>
#define message_for(a, b) \
NSLog(@#a " and " #b ": We love you!\n")
int main(void) {
message_for(Carole, Debra);
return 0;
}
When the above code is compiled and executed, it produces the following result −
2013-09-14 05:46:14.859 demo[20683] Carole and Debra: We love you!
Token Pasting (##)
The token-pasting operator (##) within a macro definition combines two arguments. It permits two separate tokens in the macro definition to be joined into a single token. For example −
#import <Foundation/Foundation.h>
#define tokenpaster(n) NSLog (@"token" #n " = %d", token##n)
int main(void) {
int token34 = 40;
tokenpaster(34);
return 0;
}
When the above code is compiled and executed, it produces the following result −
2013-09-14 05:48:14.859 demo[20683] token34 = 40
How it happened, because this example results in the following actual output from the preprocessor −
NSLog (@"token34 = %d", token34);
This example shows the concatenation of token##n into token34 and here we have used both stringize and token-pasting.
The defined() Operator
The preprocessor defined operator is used in constant expressions to determine if an identifier is defined using #define. If the specified identifier is defined, the value is true (non-zero). If the symbol is not defined, the value is false (zero). The defined operator is specified as follows −
#import <Foundation/Foundation.h>
#if !defined (MESSAGE)
#define MESSAGE "You wish!"
#endif
int main(void) {
NSLog(@"Here is the message: %s\n", MESSAGE);
return 0;
}
When the above code is compiled and executed, it produces the following result −
2013-09-14 05:48:19.859 demo[20683] Here is the message: You wish!
Parameterized Macros
One of the powerful functions of the OCPP is the ability to simulate functions using parameterized macros. For example, we might have some code to square a number as follows −
int square(int x) {
return x * x;
}
We can rewrite above code using a macro as follows −
#define square(x) ((x) * (x))
Macros with arguments must be defined using the #define directive before they can be used. The argument list is enclosed in parentheses and must immediately follow the macro name. Spaces are not allowed between macro name and open parenthesis. For example −
#import <Foundation/Foundation.h>
#define MAX(x,y) ((x) > (y) ? (x) : (y))
int main(void) {
NSLog(@"Max between 20 and 10 is %d\n", MAX(10, 20));
return 0;
}
When the above code is compiled and executed, it produces the following result −
2013-09-14 05:52:15.859 demo[20683] Max between 20 and 10 is 20
The Objective-C programming language provides a keyword called typedef, which you can use to give a type a new name. Following is an example to define a term BYTE for one-byte numbers −
typedef unsigned char BYTE;
After this type definition, the identifier BYTE can be used as an abbreviation for the type unsigned char, for example:.
BYTE b1, b2;
By convention, uppercase letters are used for these definitions to remind the user that the type name is really a symbolic abbreviation, but you can use lowercase, as follows −
typedef unsigned char byte;
Você pode usar typedefpara dar um nome ao tipo de dados definido pelo usuário também. Por exemplo, você pode usar typedef com estrutura para definir um novo tipo de dados e, em seguida, usar esse tipo de dados para definir variáveis de estrutura diretamente como segue -
#import <Foundation/Foundation.h>
typedef struct Books {
NSString *title;
NSString *author;
NSString *subject;
int book_id;
} Book;
int main() {
Book book;
book.title = @"Objective-C Programming";
book.author = @"TutorialsPoint";
book.subject = @"Programming tutorial";
book.book_id = 100;
NSLog( @"Book title : %@\n", book.title);
NSLog( @"Book author : %@\n", book.author);
NSLog( @"Book subject : %@\n", book.subject);
NSLog( @"Book Id : %d\n", book.book_id);
return 0;
}
Quando o código acima é compilado e executado, ele produz o seguinte resultado -
2013-09-12 12:21:53.745 demo[31183] Book title : Objective-C Programming
2013-09-12 12:21:53.745 demo[31183] Book author : TutorialsPoint
2013-09-12 12:21:53.745 demo[31183] Book subject : Programming tutorial
2013-09-12 12:21:53.745 demo[31183] Book Id : 100
typedef vs #define
o #define é uma diretiva Objective-C, que também é usada para definir os aliases para vários tipos de dados semelhantes a typedef mas com as seguintes diferenças -
o typedef está limitado a dar nomes simbólicos apenas a tipos, enquanto #define pode ser usado para definir alias para valores também, como você pode definir 1 como UM, etc.
o typedef a interpretação é realizada pelo compilador onde como #define as declarações são processadas pelo pré-processador.
A seguir está um uso mais simples de #define -
#import <Foundation/Foundation.h>
#define TRUE 1
#define FALSE 0
int main( ) {
NSLog( @"Value of TRUE : %d\n", TRUE);
NSLog( @"Value of FALSE : %d\n", FALSE);
return 0;
}
Quando o código acima é compilado e executado, ele produz o seguinte resultado -
2013-09-12 12:23:37.993 demo[5160] Value of TRUE : 1
2013-09-12 12:23:37.994 demo[5160] Value of FALSE : 0
A conversão de tipo é uma maneira de converter uma variável de um tipo de dados para outro. Por exemplo, se você deseja armazenar um valor longo em um número inteiro simples, você pode digitar cast long para int. Você pode converter valores de um tipo para outro explicitamente usando ocast operator como segue -
(type_name) expression
Em Objective-C, geralmente usamos CGFloat para fazer operações de ponto flutuante, que é derivado do tipo básico de float no caso de 32 bits e duplo no caso de 64 bits. Considere o exemplo a seguir, onde o operador de conversão faz com que a divisão de uma variável inteira por outra seja realizada como uma operação de ponto flutuante -
#import <Foundation/Foundation.h>
int main() {
int sum = 17, count = 5;
CGFloat mean;
mean = (CGFloat) sum / count;
NSLog(@"Value of mean : %f\n", mean );
return 0;
}
Quando o código acima é compilado e executado, ele produz o seguinte resultado -
2013-09-11 01:35:40.047 demo[20634] Value of mean : 3.400000
Deve-se notar aqui que o operador de elenco tem precedência sobre a divisão, então o valor de sum é primeiro convertido para tipo double e, finalmente, é dividido por contagem, resultando em um valor duplo.
As conversões de tipo podem ser implícitas, o que é executado pelo compilador automaticamente ou podem ser especificadas explicitamente através do uso do cast operator. É considerada uma boa prática de programação usar o operador de conversão sempre que forem necessárias conversões de tipo.
Promoção Inteira
A promoção de inteiros é o processo pelo qual os valores do tipo inteiro "menor" que int ou unsigned int são convertidos em int ou unsigned int. Considere um exemplo de adição de um caractere em um int -
#import <Foundation/Foundation.h>
int main() {
int i = 17;
char c = 'c'; /* ascii value is 99 */
int sum;
sum = i + c;
NSLog(@"Value of sum : %d\n", sum );
return 0;
}
Quando o código acima é compilado e executado, ele produz o seguinte resultado -
2013-09-11 01:38:28.492 demo[980] Value of sum : 116
Aqui, o valor de soma está chegando a 116 porque o compilador está fazendo promoção de inteiros e convertendo o valor de 'c' em ascii antes de realizar a operação de adição real.
Conversão Aritmética Usual
o usual arithmetic conversionssão executados implicitamente para converter seus valores em um tipo comum. O compilador primeiro realiza a promoção de inteiro , se os operandos ainda tiverem tipos diferentes, eles serão convertidos para o tipo que aparece mais alto na seguinte hierarquia -
As conversões aritméticas usuais não são realizadas para os operadores de atribuição, nem para os operadores lógicos && e ||. Tomemos o seguinte exemplo para entender o conceito -
#import <Foundation/Foundation.h>
int main() {
int i = 17;
char c = 'c'; /* ascii value is 99 */
CGFloat sum;
sum = i + c;
NSLog(@"Value of sum : %f\n", sum );
return 0;
}
Quando o código acima é compilado e executado, ele produz o seguinte resultado -
2013-09-11 01:41:39.192 demo[15351] Value of sum : 116.000000
Aqui, é simples entender que o primeiro c é convertido para inteiro, mas como o valor final é float, a conversão aritmética usual se aplica e o compilador converte ie c em float e os adiciona produzindo um resultado float.
Método NSLog
Para imprimir logs, usamos o método NSLog na linguagem de programação Objective-C, que usamos desde o exemplo Hello World.
Vejamos um código simples que imprimiria as palavras "Hello World" -
#import <Foundation/Foundation.h>
int main() {
NSLog(@"Hello, World! \n");
return 0;
}
Agora, quando compilarmos e executarmos o programa, obteremos o seguinte resultado.
2013-09-16 00:32:50.888 demo[16669] Hello, World!
Desativar registros em aplicativos Live
Já que os NSLogs que usamos em nosso aplicativo, eles serão impressos nos logs do dispositivo e não é bom imprimir logs em uma compilação ao vivo. Portanto, usamos uma definição de tipo para imprimir logs e podemos usá-los conforme mostrado abaixo.
#import <Foundation/Foundation.h>
#if DEBUG == 0
#define DebugLog(...)
#elif DEBUG == 1
#define DebugLog(...) NSLog(__VA_ARGS__)
#endif
int main() {
DebugLog(@"Debug log, our custom addition gets \
printed during debug only" );
NSLog(@"NSLog gets printed always" );
return 0;
}
Agora, quando compilamos e executamos o programa no modo de depuração, obteremos o seguinte resultado.
2013-09-11 02:47:07.723 demo[618] Debug log, our custom addition gets printed during debug only
2013-09-11 02:47:07.723 demo[618] NSLog gets printed always
Agora, quando compilamos e executamos o programa no modo de lançamento, obteremos o seguinte resultado.
2013-09-11 02:47:45.248 demo[3158] NSLog gets printed always
Na programação Objective-C, o tratamento de erros é fornecido com a classe NSError disponível em Foundation framework.
Um objeto NSError encapsula informações de erro mais ricas e extensíveis do que seria possível usando apenas um código de erro ou string de erro. Os principais atributos de um objeto NSError são um domínio de erro (representado por uma string), um código de erro específico do domínio e um dicionário de informações do usuário contendo informações específicas do aplicativo.
NSError
Os programas Objective-C usam objetos NSError para transmitir informações sobre erros de tempo de execução sobre os quais os usuários precisam ser informados. Na maioria dos casos, um programa exibe essas informações de erro em uma caixa de diálogo ou planilha. Mas também pode interpretar as informações e pedir ao usuário para tentar se recuperar do erro ou tentar corrigir o erro por conta própria
O objeto NSError consiste em -
Domain - O domínio de erro pode ser um dos domínios NSError predefinidos ou uma string arbitrária que descreve um domínio personalizado e o domínio não deve ser nulo.
Code - O código de erro para o erro.
User Info - O dicionário userInfo para o erro e userInfo pode ser nulo.
O exemplo a seguir mostra como criar um erro personalizado
NSString *domain = @"com.MyCompany.MyApplication.ErrorDomain";
NSString *desc = NSLocalizedString(@"Unable to complete the process", @"");
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : desc };
NSError *error = [NSError errorWithDomain:domain code:-101 userInfo:userInfo];
Aqui está o código completo do exemplo de erro acima passado como referência a um ponteiro -
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
-(NSString *) getEmployeeNameForID:(int) id withError:(NSError **)errorPtr;
@end
@implementation SampleClass
-(NSString *) getEmployeeNameForID:(int) id withError:(NSError **)errorPtr {
if(id == 1) {
return @"Employee Test Name";
} else {
NSString *domain = @"com.MyCompany.MyApplication.ErrorDomain";
NSString *desc =@"Unable to complete the process";
NSDictionary *userInfo = [[NSDictionary alloc]
initWithObjectsAndKeys:desc,
@"NSLocalizedDescriptionKey",NULL];
*errorPtr = [NSError errorWithDomain:domain code:-101
userInfo:userInfo];
return @"";
}
}
@end
int main() {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
SampleClass *sampleClass = [[SampleClass alloc]init];
NSError *error = nil;
NSString *name1 = [sampleClass getEmployeeNameForID:1 withError:&error];
if(error) {
NSLog(@"Error finding Name1: %@",error);
} else {
NSLog(@"Name1: %@",name1);
}
error = nil;
NSString *name2 = [sampleClass getEmployeeNameForID:2 withError:&error];
if(error) {
NSLog(@"Error finding Name2: %@",error);
} else {
NSLog(@"Name2: %@",name2);
}
[pool drain];
return 0;
}
No exemplo acima, retornamos um nome se o id for 1, caso contrário, definimos o objeto de erro definido pelo usuário.
Quando o código acima é compilado e executado, ele produz o seguinte resultado -
2013-09-14 18:01:00.809 demo[27632] Name1: Employee Test Name
2013-09-14 18:01:00.809 demo[27632] Error finding Name2: Unable to complete the process
É possível passar alguns valores da linha de comando para seus programas Objective-C quando eles são executados. Esses valores são chamadoscommand line arguments e muitas vezes eles são importantes para o seu programa, especialmente quando você deseja controlar o programa de fora em vez de codificar permanentemente esses valores dentro do código.
Os argumentos da linha de comando são tratados usando argumentos de função main () onde argc refere-se ao número de argumentos passados e argv[]é uma matriz de ponteiro, que aponta para cada argumento passado para o programa. A seguir está um exemplo simples, que verifica se há algum argumento fornecido a partir da linha de comando e age de acordo -
#import <Foundation/Foundation.h>
int main( int argc, char *argv[] ) {
if( argc == 2 ) {
NSLog(@"The argument supplied is %s\n", argv[1]);
} else if( argc > 2 ) {
NSLog(@"Too many arguments supplied.\n");
} else {
NSLog(@"One argument expected.\n");
}
}
Quando o código acima é compilado e executado com um único argumento, digamos "teste", ele produz o seguinte resultado.
2013-09-13 03:01:17.333 demo[7640] The argument supplied is testing
Quando o código acima é compilado e executado com dois argumentos, digamos, testing1 e testing2, ele produz o seguinte resultado.
2013-09-13 03:01:18.333 demo[7640] Too many arguments supplied.
Quando o código acima é compilado e executado sem passar nenhum argumento, ele produz o seguinte resultado.
2013-09-13 03:01:18.333 demo[7640] One argument expected
Deve-se notar que argv[0] contém o nome do próprio programa e argv[1]é um ponteiro para o primeiro argumento da linha de comando fornecido e * argv [n] é o último argumento. Se nenhum argumento for fornecido, argc será um, caso contrário, se você passar um argumento, entãoargc é definido como 2.
Você passa todos os argumentos da linha de comando separados por um espaço, mas se o próprio argumento tiver um espaço, você pode passar esses argumentos colocando-os entre aspas duplas "" ou aspas simples ''. Vamos reescrever o exemplo acima novamente, onde imprimiremos o nome do programa e também passaremos um argumento de linha de comando colocando aspas duplas -
#import <Foundation/Foundation.h>
int main( int argc, char *argv[] ) {
NSLog(@"Program name %s\n", argv[0]);
if( argc == 2 ) {
NSLog(@"The argument supplied is %s\n", argv[1]);
} else if( argc > 2 ) {
NSLog(@"Too many arguments supplied.\n");
} else {
NSLog(@"One argument expected.\n");
}
return 0;
}
Quando o código acima é compilado e executado com um único argumento separado por espaço, mas entre aspas duplas diga "Testing1 Testing2", ele produz o seguinte resultado.
2017-11-30 06:36:59.081 main[71010] Program name main
2017-11-30 06:36:59.082 main[71010] One argument expected.
O principal objetivo da linguagem de programação Objective-C é adicionar orientação a objetos à linguagem de programação C e as classes são o recurso central do Objective-C que suportam a programação orientada a objetos e são freqüentemente chamados de tipos definidos pelo usuário.
Uma classe é usada para especificar a forma de um objeto e combina representação de dados e métodos para manipular esses dados em um pacote organizado. Os dados e métodos dentro de uma classe são chamados de membros da classe.
Características do Objective-C
A classe é definida em duas seções diferentes, a saber @interface e @implementation.
Quase tudo está na forma de objetos.
Os objetos recebem mensagens e os objetos são freqüentemente chamados de receptores.
Os objetos contêm variáveis de instância.
Objetos e variáveis de instância têm escopo.
As classes ocultam a implementação de um objeto.
Propriedades são usadas para fornecer acesso a variáveis de instância de classe em outras classes.
Definições de classe Objective-C
Ao definir uma classe, você define um blueprint para um tipo de dados. Na verdade, isso não define nenhum dado, mas define o que o nome da classe significa, ou seja, em que consistirá um objeto da classe e quais operações podem ser realizadas em tal objeto.
Uma definição de classe começa com a palavra-chave @interfaceseguido pelo nome da interface (classe); e o corpo da classe, delimitado por um par de chaves. Em Objective-C, todas as classes são derivadas da classe base chamadaNSObject. É a superclasse de todas as classes Objective-C. Ele fornece métodos básicos como alocação e inicialização de memória. Por exemplo, definimos o tipo de dados Box usando a palavra-chaveclass como segue -
@interface Box:NSObject {
//Instance variables
double length; // Length of a box
double breadth; // Breadth of a box
}
@property(nonatomic, readwrite) double height; // Property
@end
As variáveis de instância são privadas e só podem ser acessadas dentro da implementação da classe.
Alocando e inicializando objetos Objective-C
Uma classe fornece os projetos para objetos, portanto, basicamente, um objeto é criado a partir de uma classe. Declaramos objetos de uma classe exatamente com o mesmo tipo de declaração com que declaramos variáveis de tipos básicos. As seguintes declarações declaram dois objetos da classe Box -
Box box1 = [[Box alloc]init]; // Create box1 object of type Box
Box box2 = [[Box alloc]init]; // Create box2 object of type Box
Ambos os objetos box1 e box2 terão sua própria cópia dos membros de dados.
Acessando os Membros de Dados
As propriedades dos objetos de uma classe podem ser acessadas usando o operador de acesso direto ao membro (.). Vamos tentar o seguinte exemplo para deixar as coisas claras -
#import <Foundation/Foundation.h>
@interface Box:NSObject {
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
}
@property(nonatomic, readwrite) double height; // Property
-(double) volume;
@end
@implementation Box
@synthesize height;
-(id)init {
self = [super init];
length = 1.0;
breadth = 1.0;
return self;
}
-(double) volume {
return length*breadth*height;
}
@end
int main() {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Box *box1 = [[Box alloc]init]; // Create box1 object of type Box
Box *box2 = [[Box alloc]init]; // Create box2 object of type Box
double volume = 0.0; // Store the volume of a box here
// box 1 specification
box1.height = 5.0;
// box 2 specification
box2.height = 10.0;
// volume of box 1
volume = [box1 volume];
NSLog(@"Volume of Box1 : %f", volume);
// volume of box 2
volume = [box2 volume];
NSLog(@"Volume of Box2 : %f", volume);
[pool drain];
return 0;
}
Quando o código acima é compilado e executado, ele produz o seguinte resultado -
2013-09-22 21:25:33.314 ClassAndObjects[387:303] Volume of Box1 : 5.000000
2013-09-22 21:25:33.316 ClassAndObjects[387:303] Volume of Box2 : 10.000000
Propriedades
Propriedades são introduzidas em Objective-C para garantir que a variável de instância da classe possa ser acessada fora da classe.
Propriedades começam com @property, que é uma palavra-chave
Ele é seguido por especificadores de acesso, que são não atômicos ou atômicos, de leitura ou somente leitura e fortes, inseguros não retidos ou fracos. Isso varia de acordo com o tipo da variável. Para qualquer tipo de ponteiro, podemos usar forte, unsafe_unretained ou fraco. Da mesma forma, para outros tipos, podemos usar readwrite ou readonly.
Isso é seguido pelo tipo de dados da variável.
Por fim, temos o nome da propriedade terminado por um ponto e vírgula.
Podemos adicionar a instrução de síntese na classe de implementação. Mas no XCode mais recente, a parte de síntese é feita pelo XCode e você não precisa incluir a instrução de síntese.
Só é possível com as propriedades que podemos acessar as variáveis de instância da classe. Na verdade, os métodos getter e setter internos são criados para as propriedades.
Por exemplo, vamos supor que temos uma propriedade @property (nonatomic ,readonly ) BOOL isDone. Sob o capô, existem setters e getters criados conforme mostrado abaixo.
-(void)setIsDone(BOOL)isDone;
-(BOOL)isDone;
Um dos conceitos mais importantes na programação orientada a objetos é o de herança. A herança nos permite definir uma classe em termos de outra classe, o que torna mais fácil criar e manter um aplicativo. Isso também fornece uma oportunidade de reutilizar a funcionalidade do código e tempo de implementação rápido.
Ao criar uma classe, em vez de escrever membros de dados e funções de membro completamente novos, o programador pode designar que a nova classe deve herdar os membros de uma classe existente. Esta classe existente é chamada debase classe, e a nova classe é chamada de derived classe.
A ideia de herança implementa o is arelação. Por exemplo, mamífero IS-A animal, cão IS-A mamífero, portanto, cão IS-A animal também e assim por diante.
Classes de base e derivadas
Objective-C permite apenas herança multinível, ou seja, pode ter apenas uma classe base, mas permite herança multinível. Todas as classes em Objective-C são derivadas da superclasseNSObject.
@interface derived-class: base-class
Considere uma classe base Person e sua classe derivada Employee como segue -
#import <Foundation/Foundation.h>
@interface Person : NSObject {
NSString *personName;
NSInteger personAge;
}
- (id)initWithName:(NSString *)name andAge:(NSInteger)age;
- (void)print;
@end
@implementation Person
- (id)initWithName:(NSString *)name andAge:(NSInteger)age {
personName = name;
personAge = age;
return self;
}
- (void)print {
NSLog(@"Name: %@", personName);
NSLog(@"Age: %ld", personAge);
}
@end
@interface Employee : Person {
NSString *employeeEducation;
}
- (id)initWithName:(NSString *)name andAge:(NSInteger)age
andEducation:(NSString *)education;
- (void)print;
@end
@implementation Employee
- (id)initWithName:(NSString *)name andAge:(NSInteger)age
andEducation: (NSString *)education {
personName = name;
personAge = age;
employeeEducation = education;
return self;
}
- (void)print {
NSLog(@"Name: %@", personName);
NSLog(@"Age: %ld", personAge);
NSLog(@"Education: %@", employeeEducation);
}
@end
int main(int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSLog(@"Base class Person Object");
Person *person = [[Person alloc]initWithName:@"Raj" andAge:5];
[person print];
NSLog(@"Inherited Class Employee Object");
Employee *employee = [[Employee alloc]initWithName:@"Raj"
andAge:5 andEducation:@"MBA"];
[employee print];
[pool drain];
return 0;
}
Quando o código acima é compilado e executado, ele produz o seguinte resultado -
2013-09-22 21:20:09.842 Inheritance[349:303] Base class Person Object
2013-09-22 21:20:09.844 Inheritance[349:303] Name: Raj
2013-09-22 21:20:09.844 Inheritance[349:303] Age: 5
2013-09-22 21:20:09.845 Inheritance[349:303] Inherited Class Employee Object
2013-09-22 21:20:09.845 Inheritance[349:303] Name: Raj
2013-09-22 21:20:09.846 Inheritance[349:303] Age: 5
2013-09-22 21:20:09.846 Inheritance[349:303] Education: MBA
Controle de acesso e herança
Uma classe derivada pode acessar todos os membros privados de sua classe base se estiver definida na classe de interface, mas não pode acessar membros privados que são definidos no arquivo de implementação.
Podemos resumir os diferentes tipos de acesso de acordo com quem pode acessá-los da seguinte maneira -
Uma classe derivada herda todos os métodos e variáveis da classe base com as seguintes exceções -
Variáveis declaradas no arquivo de implementação com a ajuda de extensões não estão acessíveis.
Os métodos declarados no arquivo de implementação com a ajuda de extensões não estão acessíveis.
No caso de a classe herdada implementar o método na classe base, então o método na classe derivada é executado.
A palavra polymorphismsignifica ter muitas formas. Normalmente, o polimorfismo ocorre quando há uma hierarquia de classes e elas estão relacionadas por herança.
O polimorfismo Objective-C significa que uma chamada a uma função-membro fará com que uma função diferente seja executada, dependendo do tipo de objeto que invoca a função.
Considere o exemplo, temos uma classe Shape que fornece a interface básica para todas as formas. Square e Rectangle são derivados da classe base Shape.
Temos o método printArea que irá mostrar sobre o recurso OOP polymorphism.
#import <Foundation/Foundation.h>
@interface Shape : NSObject {
CGFloat area;
}
- (void)printArea;
- (void)calculateArea;
@end
@implementation Shape
- (void)printArea {
NSLog(@"The area is %f", area);
}
- (void)calculateArea {
}
@end
@interface Square : Shape {
CGFloat length;
}
- (id)initWithSide:(CGFloat)side;
- (void)calculateArea;
@end
@implementation Square
- (id)initWithSide:(CGFloat)side {
length = side;
return self;
}
- (void)calculateArea {
area = length * length;
}
- (void)printArea {
NSLog(@"The area of square is %f", area);
}
@end
@interface Rectangle : Shape {
CGFloat length;
CGFloat breadth;
}
- (id)initWithLength:(CGFloat)rLength andBreadth:(CGFloat)rBreadth;
@end
@implementation Rectangle
- (id)initWithLength:(CGFloat)rLength andBreadth:(CGFloat)rBreadth {
length = rLength;
breadth = rBreadth;
return self;
}
- (void)calculateArea {
area = length * breadth;
}
@end
int main(int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Shape *square = [[Square alloc]initWithSide:10.0];
[square calculateArea];
[square printArea];
Shape *rect = [[Rectangle alloc]
initWithLength:10.0 andBreadth:5.0];
[rect calculateArea];
[rect printArea];
[pool drain];
return 0;
}
Quando o código acima é compilado e executado, ele produz o seguinte resultado -
2013-09-22 21:21:50.785 Polymorphism[358:303] The area of square is 100.000000
2013-09-22 21:21:50.786 Polymorphism[358:303] The area is 50.000000
No exemplo acima, com base na disponibilidade do método calculArea e printArea, o método na classe base ou a classe derivada executada.
O polimorfismo trata da troca de métodos entre a classe base e a classe derivada com base na implementação do método das duas classes.
Todos os programas Objective-C são compostos dos seguintes dois elementos fundamentais -
Program statements (code) - Esta é a parte de um programa que executa ações e são chamadas de métodos.
Program data - Os dados são as informações do programa que são afetadas pelas funções do programa.
Encapsulamento é um conceito de Programação Orientada a Objetos que une os dados e funções que manipulam os dados e que os mantém protegidos de interferências externas e uso indevido. O encapsulamento de dados levou ao importante conceito OOP dedata hiding.
Data encapsulation é um mecanismo de agrupamento de dados e funções que os utilizam, e data abstraction é um mecanismo de expor apenas as interfaces e ocultar os detalhes de implementação do usuário.
Objective-C suporta as propriedades de encapsulamento e ocultação de dados através da criação de tipos definidos pelo usuário, chamados classes. Por exemplo -
@interface Adder : NSObject {
NSInteger total;
}
- (id)initWithInitialNumber:(NSInteger)initialNumber;
- (void)addNumber:(NSInteger)newNumber;
- (NSInteger)getTotal;
@end
A variável total é privada e não podemos acessar de fora da classe. Isso significa que eles podem ser acessados apenas por outros membros da classe Adder e não por qualquer outra parte de seu programa. Esta é uma forma de o encapsulamento ser alcançado.
Os métodos dentro do arquivo de interface são acessíveis e de escopo público.
Existem métodos privados, que são escritos com a ajuda de extensions, que aprenderemos nos próximos capítulos.
Exemplo de encapsulamento de dados
Qualquer programa Objective-C onde você implementa uma classe com variáveis de membros públicos e privados é um exemplo de encapsulamento e abstração de dados. Considere o seguinte exemplo -
#import <Foundation/Foundation.h>
@interface Adder : NSObject {
NSInteger total;
}
- (id)initWithInitialNumber:(NSInteger)initialNumber;
- (void)addNumber:(NSInteger)newNumber;
- (NSInteger)getTotal;
@end
@implementation Adder
-(id)initWithInitialNumber:(NSInteger)initialNumber {
total = initialNumber;
return self;
}
- (void)addNumber:(NSInteger)newNumber {
total = total + newNumber;
}
- (NSInteger)getTotal {
return total;
}
@end
int main(int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Adder *adder = [[Adder alloc]initWithInitialNumber:10];
[adder addNumber:5];
[adder addNumber:4];
NSLog(@"The total is %ld",[adder getTotal]);
[pool drain];
return 0;
}
Quando o código acima é compilado e executado, ele produz o seguinte resultado -
2013-09-22 21:17:30.485 DataEncapsulation[317:303] The total is 19
A classe acima adiciona números e retorna a soma. Os membros públicosaddNum e getTotal são as interfaces para o mundo exterior e um usuário precisa conhecê-las para usar a classe. O membro privadototal é algo que está escondido do mundo exterior, mas é necessário para que a classe funcione corretamente.
Estratégia de Projeto
A maioria de nós aprendeu por meio de experiências amargas a tornar os alunos privados por padrão, a menos que realmente precisemos expô-los. Isso é bomencapsulation.
É importante entender o encapsulamento de dados, pois é um dos principais recursos de todas as linguagens de Programação Orientada a Objetos (OOP), incluindo Objective-C.
Às vezes, você pode descobrir que deseja estender uma classe existente, adicionando um comportamento que é útil apenas em certas situações. Para adicionar essa extensão às classes existentes, Objective-C fornececategories e extensions.
Se você precisar adicionar um método a uma classe existente, talvez, para adicionar funcionalidade para tornar mais fácil fazer algo em seu próprio aplicativo, a maneira mais fácil é usar uma categoria.
A sintaxe para declarar uma categoria usa a palavra-chave @interface, assim como uma descrição de classe Objective-C padrão, mas não indica qualquer herança de uma subclasse. Em vez disso, ele especifica o nome da categoria entre parênteses, como este -
@interface ClassName (CategoryName)
@end
Características da categoria
Uma categoria pode ser declarada para qualquer classe, mesmo se você não tiver o código-fonte da implementação original.
Todos os métodos que você declarar em uma categoria estarão disponíveis para todas as instâncias da classe original, bem como quaisquer subclasses da classe original.
Em tempo de execução, não há diferença entre um método adicionado por uma categoria e um que é implementado pela classe original.
Agora, vamos dar uma olhada em um exemplo de implementação de categoria. Vamos adicionar uma categoria à classe NSString do Cocoa. Esta categoria possibilitará adicionar um novo método getCopyRightString que nos ajuda a retornar a string de copyright. É mostrado abaixo.
#import <Foundation/Foundation.h>
@interface NSString(MyAdditions)
+(NSString *)getCopyRightString;
@end
@implementation NSString(MyAdditions)
+(NSString *)getCopyRightString {
return @"Copyright TutorialsPoint.com 2013";
}
@end
int main(int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString *copyrightString = [NSString getCopyRightString];
NSLog(@"Accessing Category: %@",copyrightString);
[pool drain];
return 0;
}
Agora, quando compilarmos e executarmos o programa, obteremos o seguinte resultado.
2013-09-22 21:19:12.125 Categories[340:303] Accessing Category: Copyright TutorialsPoint.com 2013
Mesmo que todos os métodos adicionados por uma categoria estejam disponíveis para todas as instâncias da classe e suas subclasses, você precisará importar o arquivo de cabeçalho da categoria em qualquer arquivo de código-fonte onde deseja usar os métodos adicionais, caso contrário, você encontrará avisos e erros do compilador.
Em nosso exemplo, uma vez que temos apenas uma única classe, não incluímos nenhum arquivo de cabeçalho, neste caso devemos incluir os arquivos de cabeçalho conforme dito acima.
Antes de começar sobre o Posing em Objective-C, gostaria de informar que o Posing foi declarado obsoleto no Mac OS X 10.5 e não está disponível para uso posteriormente. Portanto, aqueles que não estão preocupados com esses métodos obsoletos podem pular este capítulo.
Objective-C permite que uma classe substitua completamente outra classe dentro de um programa. Diz-se que a classe substituta "se apresenta como" a classe-alvo.
Para as versões que suportam poses, todas as mensagens enviadas para a classe de destino são recebidas pela classe de pose.
NSObject contém o método poseAsClass: que nos permite substituir a classe existente como dito acima.
Restrições em poses
Uma classe só pode se passar por uma de suas superclasses diretas ou indiretas.
A classe de posicionamento não deve definir nenhuma nova variável de instância que esteja ausente da classe de destino (embora possa definir ou substituir métodos).
A classe alvo pode não ter recebido nenhuma mensagem antes da apresentação.
Uma classe de apresentação pode chamar métodos substituídos por meio de super, incorporando assim a implementação da classe de destino.
Uma classe de poses pode substituir métodos definidos em categorias.
#import <Foundation/Foundation.h>
@interface MyString : NSString
@end
@implementation MyString
- (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target
withString:(NSString *)replacement {
NSLog(@"The Target string is %@",target);
NSLog(@"The Replacement string is %@",replacement);
}
@end
int main() {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
[MyString poseAsClass:[NSString class]];
NSString *string = @"Test";
[string stringByReplacingOccurrencesOfString:@"a" withString:@"c"];
[pool drain];
return 0;
}
Agora, quando compilamos e executamos o programa em um Mac OS X mais antigo (V_10.5 ou anterior), obteremos o seguinte resultado.
2013-09-22 21:23:46.829 Posing[372:303] The Target string is a
2013-09-22 21:23:46.830 Posing[372:303] The Replacement string is c
No exemplo acima, apenas poluímos o método original com nossa implementação e isso será afetado em todas as operações NSString com o método acima.
Uma extensão de classe tem alguma semelhança com uma categoria, mas só pode ser adicionada a uma classe para a qual você tenha o código-fonte no momento da compilação (a classe é compilada ao mesmo tempo que a extensão da classe).
Os métodos declarados por uma extensão de classe são implementados no bloco de implementação da classe original, portanto, você não pode, por exemplo, declarar uma extensão de classe em uma classe de estrutura, como uma classe Cocoa ou Cocoa Touch como NSString.
As extensões são, na verdade, categorias sem o nome da categoria. Muitas vezes é referido comoanonymous categories.
A sintaxe para declarar uma extensão usa a palavra-chave @interface, assim como uma descrição de classe Objective-C padrão, mas não indica qualquer herança de uma subclasse. Em vez disso, ele apenas adiciona parênteses, como mostrado abaixo -
@interface ClassName ()
@end
Características das extensões
Uma extensão não pode ser declarada para nenhuma classe, apenas para as classes que temos implementação original do código-fonte.
Uma extensão está adicionando métodos privados e variáveis privadas que são apenas específicos para a classe.
Qualquer método ou variável declarada dentro das extensões não é acessível nem mesmo para as classes herdadas.
Exemplo de extensões
Vamos criar uma classe SampleClass que possui uma extensão. Na extensão, vamos ter uma variável privada internalID.
Então, vamos ter um método getExternalID que retorna o externalID depois de processar o internalID.
O exemplo é mostrado abaixo e não funcionará no compilador online.
#import <Foundation/Foundation.h>
@interface SampleClass : NSObject {
NSString *name;
}
- (void)setInternalID;
- (NSString *)getExternalID;
@end
@interface SampleClass() {
NSString *internalID;
}
@end
@implementation SampleClass
- (void)setInternalID {
internalID = [NSString stringWithFormat:
@"UNIQUEINTERNALKEY%dUNIQUEINTERNALKEY",arc4random()%100];
}
- (NSString *)getExternalID {
return [internalID stringByReplacingOccurrencesOfString:
@"UNIQUEINTERNALKEY" withString:@""];
}
@end
int main(int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
SampleClass *sampleClass = [[SampleClass alloc]init];
[sampleClass setInternalID];
NSLog(@"ExternalID: %@",[sampleClass getExternalID]);
[pool drain];
return 0;
}
Agora, quando compilarmos e executarmos o programa, obteremos o seguinte resultado.
2013-09-22 21:18:31.754 Extensions[331:303] ExternalID: 51
No exemplo acima, podemos ver que o internalID não é retornado diretamente. Aqui, removemos UNIQUEINTERNALKEY e apenas disponibilizamos o valor restante para o método getExternalID.
O exemplo acima usa apenas uma operação de string, mas pode ter muitos recursos como criptografia / descriptografia e assim por diante.
Objective-C permite definir protocolos, que declaram os métodos a serem usados para uma situação particular. Os protocolos são implementados nas classes em conformidade com o protocolo.
Um exemplo simples seria uma classe de manipulação de URL de rede, ela terá um protocolo com métodos como o método delegado processCompleted que indica a classe de chamada assim que a operação de busca de URL de rede terminar.
Uma sintaxe de protocolo é mostrada abaixo.
@protocol ProtocolName
@required
// list of required methods
@optional
// list of optional methods
@end
Os métodos em palavra-chave @required deve ser implementado nas classes que estão em conformidade com o protocolo e os métodos sob @optional palavras-chave são opcionais para implementar.
Aqui está a sintaxe da classe em conformidade com o protocolo
@interface MyClass : NSObject <MyProtocol>
...
@end
Isso significa que qualquer instância de MyClass responderá não apenas aos métodos declarados especificamente na interface, mas que MyClass também fornece implementações para os métodos necessários em MyProtocol. Não há necessidade de declarar novamente os métodos de protocolo na interface da classe - a adoção do protocolo é suficiente.
Se você precisar que uma classe adote vários protocolos, poderá especificá-los como uma lista separada por vírgulas. Temos um objeto delegado que contém a referência do objeto de chamada que implementa o protocolo.
Um exemplo é mostrado abaixo.
#import <Foundation/Foundation.h>
@protocol PrintProtocolDelegate
- (void)processCompleted;
@end
@interface PrintClass :NSObject {
id delegate;
}
- (void) printDetails;
- (void) setDelegate:(id)newDelegate;
@end
@implementation PrintClass
- (void)printDetails {
NSLog(@"Printing Details");
[delegate processCompleted];
}
- (void) setDelegate:(id)newDelegate {
delegate = newDelegate;
}
@end
@interface SampleClass:NSObject<PrintProtocolDelegate>
- (void)startAction;
@end
@implementation SampleClass
- (void)startAction {
PrintClass *printClass = [[PrintClass alloc]init];
[printClass setDelegate:self];
[printClass printDetails];
}
-(void)processCompleted {
NSLog(@"Printing Process Completed");
}
@end
int main(int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
SampleClass *sampleClass = [[SampleClass alloc]init];
[sampleClass startAction];
[pool drain];
return 0;
}
Agora, quando compilarmos e executarmos o programa, obteremos o seguinte resultado.
2013-09-22 21:15:50.362 Protocols[275:303] Printing Details
2013-09-22 21:15:50.364 Protocols[275:303] Printing Process Completed
No exemplo acima, vimos como os métodos delgate são chamados e executados. Começa com startAction, uma vez que o processo é concluído, o método delegado processCompleted é chamado para indicar que a operação foi concluída.
Em qualquer aplicativo iOS ou Mac, nunca teremos um programa implementado sem um delegado. Portanto, é importante entendermos o uso dos delegados. Objetos delegados devem usar o tipo de propriedade unsafe_unretained para evitar vazamentos de memória.
A vinculação dinâmica determina o método a ser invocado no tempo de execução em vez de no tempo de compilação. A vinculação dinâmica também é conhecida como vinculação tardia.
Em Objective-C, todos os métodos são resolvidos dinamicamente no tempo de execução. O código exato executado é determinado pelo nome do método (o seletor) e pelo objeto receptor.
A ligação dinâmica permite o polimorfismo. Por exemplo, considere uma coleção de objetos incluindo Retângulo e Quadrado. Cada objeto tem sua própria implementação de um método printArea.
No fragmento de código a seguir, o código real que deve ser executado pela expressão [anObject printArea] é determinado em tempo de execução. O sistema de tempo de execução usa o seletor para o método executado para identificar o método apropriado em qualquer classe de umObject.
Vejamos um código simples que explicaria a vinculação dinâmica.
#import <Foundation/Foundation.h>
@interface Square:NSObject {
float area;
}
- (void)calculateAreaOfSide:(CGFloat)side;
- (void)printArea;
@end
@implementation Square
- (void)calculateAreaOfSide:(CGFloat)side {
area = side * side;
}
- (void)printArea {
NSLog(@"The area of square is %f",area);
}
@end
@interface Rectangle:NSObject {
float area;
}
- (void)calculateAreaOfLength:(CGFloat)length andBreadth:(CGFloat)breadth;
- (void)printArea;
@end
@implementation Rectangle
- (void)calculateAreaOfLength:(CGFloat)length andBreadth:(CGFloat)breadth {
area = length * breadth;
}
- (void)printArea {
NSLog(@"The area of Rectangle is %f",area);
}
@end
int main() {
Square *square = [[Square alloc]init];
[square calculateAreaOfSide:10.0];
Rectangle *rectangle = [[Rectangle alloc]init];
[rectangle calculateAreaOfLength:10.0 andBreadth:5.0];
NSArray *shapes = [[NSArray alloc]initWithObjects: square, rectangle,nil];
id object1 = [shapes objectAtIndex:0];
[object1 printArea];
id object2 = [shapes objectAtIndex:1];
[object2 printArea];
return 0;
}
Agora, quando compilarmos e executarmos o programa, obteremos o seguinte resultado.
2013-09-28 07:42:29.821 demo[4916] The area of square is 100.000000
2013-09-28 07:42:29.821 demo[4916] The area of Rectangle is 50.000000
Como você pode ver no exemplo acima, o método printArea é selecionado dinamicamente no tempo de execução. É um exemplo de vinculação dinâmica e é bastante útil em muitas situações ao lidar com tipos de objetos semelhantes.
Podemos criar subclasses dentro de um cluster de classes que define uma classe que embute um objeto. Esses objetos de classe são objetos compostos.
Então você deve estar se perguntando o que é um cluster de classe. Então, primeiro veremos o que é um cluster de classe.
Clusters de classe
Os clusters de classes são um padrão de design que a estrutura Foundation faz uso extensivo. Os clusters de classes agrupam várias subclasses concretas privadas sob uma superclasse pública abstrata. O agrupamento de classes dessa maneira simplifica a arquitetura publicamente visível de uma estrutura orientada a objetos sem reduzir sua riqueza funcional. Os clusters de classes são baseados no padrão de design Abstract Factory.
Para simplificar, em vez de criar várias classes para funções semelhantes, criamos uma única classe que cuidará de seu tratamento com base no valor de entrada.
Por exemplo, em NSNumber temos muitos clusters de classes como char, int, bool e assim por diante. Nós agrupamos todos eles em uma única classe que se encarrega de lidar com operações semelhantes em uma única classe. NSNumber, na verdade, envolve o valor desses tipos primitivos em objetos.
Então, o que é exatamente objeto composto?
Incorporando um objeto de cluster privado em um objeto de nosso próprio projeto, criamos um objeto composto. Este objeto de composição pode contar com o objeto de cluster para sua funcionalidade básica, apenas interceptando mensagens que o objeto de composição deseja tratar de alguma maneira particular. Essa arquitetura reduz a quantidade de código que devemos escrever e permite que você aproveite as vantagens do código testado fornecido pelo Foundation Framework.
Isso é explicado na figura a seguir.
O objeto de composição deve se declarar uma subclasse da superclasse abstrata do cluster. Como uma subclasse, ele deve sobrescrever os métodos primitivos da superclasse. Ele também pode substituir métodos derivados, mas isso não é necessário porque os métodos derivados funcionam por meio dos primitivos.
O método de contagem da classe NSArray é um exemplo; a implementação do objeto interveniente de um método que ele substitui pode ser tão simples quanto -
- (unsigned)count {
return [embeddedObject count];
}
No exemplo acima, o objeto incorporado é, na verdade, do tipo NSArray.
Um exemplo de objeto composto
Agora, para ver um exemplo completo, vejamos o exemplo da documentação da Apple que é fornecido abaixo.
#import <Foundation/Foundation.h>
@interface ValidatingArray : NSMutableArray {
NSMutableArray *embeddedArray;
}
+ validatingArray;
- init;
- (unsigned)count;
- objectAtIndex:(unsigned)index;
- (void)addObject:object;
- (void)replaceObjectAtIndex:(unsigned)index withObject:object;
- (void)removeLastObject;
- (void)insertObject:object atIndex:(unsigned)index;
- (void)removeObjectAtIndex:(unsigned)index;
@end
@implementation ValidatingArray
- init {
self = [super init];
if (self) {
embeddedArray = [[NSMutableArray allocWithZone:[self zone]] init];
}
return self;
}
+ validatingArray {
return [[self alloc] init] ;
}
- (unsigned)count {
return [embeddedArray count];
}
- objectAtIndex:(unsigned)index {
return [embeddedArray objectAtIndex:index];
}
- (void)addObject:(id)object {
if (object != nil) {
[embeddedArray addObject:object];
}
}
- (void)replaceObjectAtIndex:(unsigned)index withObject:(id)object; {
if (index <[embeddedArray count] && object != nil) {
[embeddedArray replaceObjectAtIndex:index withObject:object];
}
}
- (void)removeLastObject; {
if ([embeddedArray count] > 0) {
[embeddedArray removeLastObject];
}
}
- (void)insertObject:(id)object atIndex:(unsigned)index; {
if (object != nil) {
[embeddedArray insertObject:object atIndex:index];
}
}
- (void)removeObjectAtIndex:(unsigned)index; {
if (index <[embeddedArray count]) {
[embeddedArray removeObjectAtIndex:index];
}
}
@end
int main() {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
ValidatingArray *validatingArray = [ValidatingArray validatingArray];
[validatingArray addObject:@"Object1"];
[validatingArray addObject:@"Object2"];
[validatingArray addObject:[NSNull null]];
[validatingArray removeObjectAtIndex:2];
NSString *aString = [validatingArray objectAtIndex:1];
NSLog(@"The value at Index 1 is %@",aString);
[pool drain];
return 0;
}
Agora, quando compilarmos e executarmos o programa, obteremos o seguinte resultado.
2013-09-28 22:03:54.294 demo[6247] The value at Index 1 is Object2
No exemplo acima, podemos ver que validar a função única do array não permitiria adicionar objetos nulos que levariam a um travamento no cenário normal. Mas nosso array de validação cuida disso. Da mesma forma, cada um dos métodos de validação de array adiciona processos de validação além da sequência normal de operações.
Se você consultar a documentação da Apple, poderá ver os detalhes da estrutura Foundation conforme fornecido abaixo.
A estrutura Foundation define uma camada base de classes Objective-C. Além de fornecer um conjunto de classes de objetos primitivos úteis, ele introduz vários paradigmas que definem funcionalidades não cobertas pela linguagem Objective-C. A estrutura da Fundação foi projetada com esses objetivos em mente -
Fornece um pequeno conjunto de classes de utilitários básicos.
Facilite o desenvolvimento de software, introduzindo convenções consistentes para itens como desalocação.
Suporte a strings Unicode, persistência de objetos e distribuição de objetos.
Fornece um nível de independência do sistema operacional para melhorar a portabilidade.
O framework foi desenvolvido pela NeXTStep, que foi adquirida pela Apple e essas classes básicas passaram a fazer parte do Mac OS X e iOS.
Por ter sido desenvolvido pela NeXTStep, possui o prefixo de classe "NS".
Usamos o Foundation Framework em todos os nossos programas de amostra. É quase obrigatório usar o Foundation Framework.
Geralmente, usamos algo como #import <Foundation/NSString.h> para importar uma classe Objective-C, mas para evitar a importação de muitas classes, é tudo importado em #import <Foundation/Foundation.h>.
NSObject é a classe base de todos os objetos, incluindo as classes do kit de base. Ele fornece os métodos para gerenciamento de memória. Ele também fornece interface básica para o sistema de tempo de execução e capacidade de se comportar como objetos Objective-C. Não tem nenhuma classe base e é a raiz de todas as classes.
Aulas básicas com base na funcionalidade
Sr. Não. | Tipo de Loop e Descrição |
---|---|
1 | Armazenamento de dados NSArray, NSDictionary e NSSet fornecem armazenamento para objetos Objective-C de qualquer classe. |
2 | Texto e strings NSCharacterSet representa vários agrupamentos de caracteres que são usados pelas classes NSString e NSScanner. As classes NSString representam strings de texto e fornecem métodos para pesquisar, combinar e comparar strings. Um objeto NSScanner é usado para verificar números e palavras de um objeto NSString. |
3 | Datas e horas As classes NSDate, NSTimeZone e NSCalendar armazenam horas e datas e representam informações do calendário. Eles oferecem métodos para calcular diferenças de data e hora. Junto com NSLocale, eles fornecem métodos para exibir datas e horas em vários formatos e para ajustar horas e datas com base na localização no mundo. |
4 | Manipulação de exceção O tratamento de exceções é usado para lidar com situações inesperadas e é oferecido em Objective-C com NSException. |
5 | Manipulação de arquivos O tratamento de arquivos é feito com a ajuda da classe NSFileManager. |
6 | Sistema de carregamento de URL Um conjunto de classes e protocolos que fornecem acesso a protocolos comuns da Internet. |
A enumeração rápida é um recurso do Objective-C que ajuda na enumeração por meio de uma coleção. Portanto, para saber sobre a enumeração rápida, precisamos primeiro saber sobre a coleção, que será explicada na seção seguinte.
Coleções em Objective-C
Coleções são construções fundamentais. Ele é usado para manter e gerenciar outros objetos. Todo o propósito de uma coleção é fornecer uma maneira comum de armazenar e recuperar objetos com eficiência.
Existem vários tipos diferentes de coleções. Embora todos cumpram o mesmo propósito de serem capazes de segurar outros objetos, eles diferem principalmente na forma como os objetos são recuperados. As coleções mais comuns usadas em Objective-C são -
- NSSet
- NSArray
- NSDictionary
- NSMutableSet
- NSMutableArray
- NSMutableDictionary
Se você quiser saber mais sobre essas estruturas, consulte armazenamento de dados no Foundation Framework .
Sintaxe de enumeração rápida
for (classType variable in collectionObject ) {
statements
}
Aqui está um exemplo de enumeração rápida.
#import <Foundation/Foundation.h>
int main() {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSArray *array = [[NSArray alloc]
initWithObjects:@"string1", @"string2",@"string3",nil];
for(NSString *aString in array) {
NSLog(@"Value: %@",aString);
}
[pool drain];
return 0;
}
Agora, quando compilarmos e executarmos o programa, obteremos o seguinte resultado.
2013-09-28 06:26:22.835 demo[7426] Value: string1
2013-09-28 06:26:22.836 demo[7426] Value: string2
2013-09-28 06:26:22.836 demo[7426] Value: string3
Como você pode ver na saída, cada um dos objetos no array é impresso em uma ordem.
Enumeração rápida para trás
for (classType variable in [collectionObject reverseObjectEnumerator] ) {
statements
}
Aqui está um exemplo de reverseObjectEnumerator na enumeração rápida.
#import <Foundation/Foundation.h>
int main() {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSArray *array = [[NSArray alloc]
initWithObjects:@"string1", @"string2",@"string3",nil];
for(NSString *aString in [array reverseObjectEnumerator]) {
NSLog(@"Value: %@",aString);
}
[pool drain];
return 0;
}
Agora, quando compilarmos e executarmos o programa, obteremos o seguinte resultado.
2013-09-28 06:27:51.025 demo[12742] Value: string3
2013-09-28 06:27:51.025 demo[12742] Value: string2
2013-09-28 06:27:51.025 demo[12742] Value: string1
Como você pode ver na saída, cada um dos objetos na matriz é impresso, mas na ordem inversa em comparação com a enumeração rápida normal.
O gerenciamento de memória é um dos processos mais importantes em qualquer linguagem de programação. É o processo pelo qual a memória dos objetos é alocada quando são necessários e desalocada quando não são mais necessários.
Gerenciar a memória do objeto é uma questão de desempenho; se um aplicativo não liberar objetos desnecessários, sua área de cobertura de memória aumentará e o desempenho será prejudicado.
As técnicas de gerenciamento de memória Objective-C podem ser amplamente classificadas em dois tipos.
- "Manual Retain-Release" ou MRR
- "Contagem automática de referência" ou ARC
"Manual Retain-Release" ou MRR
No MRR, gerenciamos explicitamente a memória, controlando os objetos por conta própria. Isso é implementado usando um modelo, conhecido como contagem de referência, que a classe Foundation NSObject fornece em conjunto com o ambiente de tempo de execução.
A única diferença entre o MRR e o ARC é que a retenção e a liberação são feitas por nós manualmente no primeiro, enquanto no segundo é feito automaticamente.
A figura a seguir representa um exemplo de como o gerenciamento de memória funciona em Objective-C.
O ciclo de vida da memória do objeto Classe A é mostrado na figura acima. Como você pode ver, a contagem de retenção é mostrada abaixo do objeto, quando a contagem de retenção de um objeto torna-se 0, o objeto é liberado completamente e sua memória é desalocada para outros objetos usarem.
O objeto Classe A é criado primeiro usando o método aloc / init disponível em NSObject. Agora, a contagem de retenção torna-se 1.
Agora, a classe B retém o objeto da Classe A e a contagem retida do objeto da Classe A torna-se 2.
Em seguida, a Classe C faz uma cópia do objeto. Agora, ele é criado como outra instância da Classe A com os mesmos valores para as variáveis de instância. Aqui, a contagem de retenção é 1 e não a contagem de retenção do objeto original. Isso é representado pela linha pontilhada na figura.
O objeto copiado é liberado pela Classe C usando o método de liberação e a contagem de retenção torna-se 0 e, portanto, o objeto é destruído.
No caso do objeto Classe A inicial, a contagem de retenção é 2 e ele deve ser liberado duas vezes para ser destruído. Isso é feito por declarações de liberação de Classe A e Classe B que diminuem a contagem de retenção para 1 e 0, respectivamente. Finalmente, o objeto é destruído.
Regras básicas de MRR
Nós possuímos qualquer objeto que criamos: criamos um objeto usando um método cujo nome começa com "alloc", "new", "copy" ou "mutableCopy"
Podemos assumir a propriedade de um objeto usando reter: Um objeto recebido normalmente tem a garantia de permanecer válido dentro do método em que foi recebido, e esse método também pode retornar o objeto com segurança para seu invocador. Usamos reter em duas situações -
Na implementação de um método acessador ou método init, para obter a propriedade de um objeto que queremos armazenar como um valor de propriedade.
Para evitar que um objeto seja invalidado como efeito colateral de alguma outra operação.
Quando não precisarmos mais dele, devemos renunciar à propriedade de um objeto que possuímos: Renunciamos à propriedade de um objeto enviando-lhe uma mensagem de liberação ou uma mensagem de liberação automática. Na terminologia do Cocoa, renunciar à propriedade de um objeto é, portanto, normalmente referido como "liberação" de um objeto.
Você não deve renunciar à propriedade de um objeto que não possui: isso é apenas o corolário das regras de política anteriores declaradas explicitamente.
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
- (void)sampleMethod;
@end
@implementation SampleClass
- (void)sampleMethod {
NSLog(@"Hello, World! \n");
}
- (void)dealloc {
NSLog(@"Object deallocated");
[super dealloc];
}
@end
int main() {
/* my first program in Objective-C */
SampleClass *sampleClass = [[SampleClass alloc]init];
[sampleClass sampleMethod];
NSLog(@"Retain Count after initial allocation: %d",
[sampleClass retainCount]);
[sampleClass retain];
NSLog(@"Retain Count after retain: %d", [sampleClass retainCount]);
[sampleClass release];
NSLog(@"Retain Count after release: %d", [sampleClass retainCount]);
[sampleClass release];
NSLog(@"SampleClass dealloc will be called before this");
// Should set the object to nil
sampleClass = nil;
return 0;
}
Quando compilarmos o programa acima, obteremos a seguinte saída.
2013-09-28 04:39:52.310 demo[8385] Hello, World!
2013-09-28 04:39:52.311 demo[8385] Retain Count after initial allocation: 1
2013-09-28 04:39:52.311 demo[8385] Retain Count after retain: 2
2013-09-28 04:39:52.311 demo[8385] Retain Count after release: 1
2013-09-28 04:39:52.311 demo[8385] Object deallocated
2013-09-28 04:39:52.311 demo[8385] SampleClass dealloc will be called before this
"Contagem automática de referência" ou ARC
Na contagem automática de referência ou ARC, o sistema usa o mesmo sistema de contagem de referência que o MRR, mas insere as chamadas de método de gerenciamento de memória apropriadas para nós no momento da compilação. Somos fortemente encorajados a usar o ARC para novos projetos. Se usarmos o ARC, normalmente não há necessidade de entender a implementação subjacente descrita neste documento, embora possa ser útil em algumas situações. Para obter mais informações sobre o ARC, consulte Transitioning to ARC Release Notes.
Conforme mencionado acima, no ARC, não precisamos adicionar métodos de liberação e retenção, pois isso será feito pelo compilador. Na verdade, o processo subjacente de Objective-C ainda é o mesmo. Ele usa as operações de retenção e liberação internamente, tornando mais fácil para o desenvolvedor codificar sem se preocupar com essas operações, o que reduzirá a quantidade de código escrito e a possibilidade de vazamentos de memória.
Havia outro princípio chamado coleta de lixo, que é usado no Mac OS-X junto com o MRR, mas desde sua depreciação no OS-X Mountain Lion, ele não foi discutido junto com o MRR. Além disso, os objetos iOS nunca tiveram o recurso de coleta de lixo. E com o ARC, não há uso de coleta de lixo no OS-X também.
Aqui está um exemplo simples de ARC. Observe que isso não funcionará no compilador online, pois não oferece suporte a ARC.
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
- (void)sampleMethod;
@end
@implementation SampleClass
- (void)sampleMethod {
NSLog(@"Hello, World! \n");
}
- (void)dealloc {
NSLog(@"Object deallocated");
}
@end
int main() {
/* my first program in Objective-C */
@autoreleasepool {
SampleClass *sampleClass = [[SampleClass alloc]init];
[sampleClass sampleMethod];
sampleClass = nil;
}
return 0;
}
Quando compilarmos o programa acima, obteremos a seguinte saída.
2013-09-28 04:45:47.310 demo[8385] Hello, World!
2013-09-28 04:45:47.311 demo[8385] Object deallocated