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