sábado, 21 de dezembro de 2013

Methods in Objective-C

Write in english is not so good to me because my sense of humor will be lost... :)
But, when we write in english everybody believes. Then, I can put here a lot of lies and nobody will make a question.

Lets start... Today my post is about how call methods in Objective-C. The syntax is a little different from Java, that use a dot notation, like:

   myObject.myMethod(list of parameters)

In Objective-C we use [ ] (brackets) to call methods, like this:

   [myObject myMethod]

Is very common to see code with two or more brackets because we are trying to get an object and then call a method of this object. In the next code, [myObject getAnObject] returns an object, then I call otherMethod from this object:

[[myObject getAnObject] otherMethod]

Lets see an example. I modeled a SpaceCraft' class, and the code (.m and .h) is showed below:

#import <Foundation/Foundation.h>

@interface SpaceCraft : NSObject

@property double speed;


@end


#import "SpaceCraft.h"
#import "BlackHole.h"
#import "Planet.m"

@interface SpaceCraft()

@property (nonatomic, strong) BlackHole *hole;

- (void) travelTo:(Planet *)planet withSpeed:(double) speed;

@end

@implementation SpaceCraft

@synthesize speed;

- (void) travelTo:(Planet *)planet withSpeed:(double) speed
{
    
}

- (void) orbitSpaceCraft:(Planet *) planet atAltitude:(double) miles
{
    double actualSpeed = [self speed];
    Planet *saturn = [[Planet alloc] init];
    if ([[self hole] tooClose:self]) {
        [self travelTo:saturn withSpeed:actualSpeed];
    }
}


@end

In the @interface we can put private elements. I created a property called "hole" and a method travelTo:withSpeed. But, I want you to pay attention to method orbitSpaceCraft:atAltitude. Let's analyze details of this method.

The code below create a variable actualSpeed and put the value of the @property speed. How?

    double actualSpeed = [self speed];

Because [self speed] calls the method get (remember that I created this method when I wrote @synthesize speed)

To create an instance, we normally use a syntax like this:

    Planet *saturn = [[Planet allocinit];

[Planet alloc] returns an object and then we call init method to initialize. Of course, there are differents ways to create an instance, but this is the most common when we create our class. 

What are we doing in the code below?

    if ([[self holetooClose:self]) {

Well, because we are using the reserved word IF we can imagine that everything returns a boolean type. It's true! But, let's talk about it.

[self hole] called the method get and it returns a BlackHole object, then I called a method tooClose from this object. The code below shows the definition of this method in the BlackHole class:

- (BOOL) tooClose:(NSObject *) object;


Finally, in the code below I called the method travelTo:withSpeed. This syntax is closely to Java or C# way. The difference is the use of dot notation:

  [self travelTo:saturn withSpeed:actualSpeed];

However, we can use dot notation to properties in Objective-C. See the implementation of travelTo:withSpeed:

- (void) orbitSpaceCraft:(Planet *) planet atAltitude:(double) miles
{
    double actualSpeed = self.speed;
    Planet *saturn = [[Planet alloc] init];
    if ([self.hole tooClose:self]) {
        self.speed = actualSpeed * 2;
        [self travelTo:saturn withSpeed:actualSpeed];
    }

}

We can put object.property. This is very useful to write code.

If you are careful, you noted that travelTo:withSpeed has different implementations. I doubled the speed to scape from BlackHole (because i want to continue to write this blog). The question is, how can I do this without dot notation?

In the next post we'll talk about constructors (init methods).

See you soon...


sábado, 14 de dezembro de 2013

Atributos em Objective-C

Como qualquer outra linguagem com paradigma OO, o Objective-C permite a criação de atributos nas classes para que eles possam armazenar dados.

Para quem está acostumado, por exemplo, com atributos e métodos get e set da linguagem Java, o mais próximo que podemos fazer em Objective-C é o que pode ser visto abaixo.
No arquivo .h definimos o atributo numEscotilhas e os métodos get (numeroEscotilhas) e set (setNumeroEscotilhas:)

#import "Veiculo.h"
#import "Planeta.h"

@interface Nave : Veiculo

(int) numeroEscotilhas;

- (void) orbitarNave:(Planeta *) planeta naAltitude:(double)km;

- (void) setNumeroEscotilhas:(int) num;
- (int) numeroEscotilhas;

@end

No arquivo .m fazemos a implementação dos métodos:

#import "Nave.h"

@interface Nave

@implementation Nave

- (void) orbitarNave:(Planeta *) planeta naAltitude:(double)km {
    
}

- (void) setNumeroEscotilhas:(int) num {
    numeroEscotilhas = num;
}

- (int) numeroEscotilhas {
    return numeroEscotilhas;
}


@end

Realmente, é bastante parecido com o que fazemos em Java. Entretanto, com Objetive-C podemos fazer esse trabalho de uma forma mais simples.
Suponha que desejamos criar um atributo para a velocidade da nave. A definição ficaria da seguinte forma:

#import "Veiculo.h"
#import "Planeta.h"

@interface Nave : Veiculo

@property (nonatomic) int velocidade;

- (void) orbitarNave:(Planeta *) planeta naAltitude:(double)km;


@end

Definimos uma @property e usamos (nonatomic) para especificar que o atributo não será thread-safe, que é o caso mais comum os atributos das classes. Já o arquivo .m ficará da seguinte maneira:

#import "Nave.h"

@implementation Nave

@synthesize velocidade = _velocidade;

- (void) orbitarNave:(Planeta *) planeta naAltitude:(double)km {
    
}


@end

Usamos @synthesize para definir os métodos get e set "automaticamente" pelo compilador, isto é, não vamos fazer os métodos manualmente, mas eles existem e tem a seguinte forma:

#import "Nave.h"

@implementation Nave

@synthesize velocidade = _velocidade;

- (void) orbitarNave:(Planeta *) planeta naAltitude:(double)km {
    
}

- (void) setVelocidade:(int)velocidade {
    _velocidade = velocidade;
}

- (int) velocidade{
    return _velocidade;
}


@end

Uma coisa que você pode estranhar é o fato de criar uma "nova" variável com underscore (_velocidade). Isto acontece para o compilador não se confundir se estamos chamando o método ou a variável (lembre que o método get tem o nome nome da property).

Nada impede, entretanto, que criemos nossa própria versão de um (ou dos dois) métodos. Imagine que não quero que a velocidade seja negativa, sendo assim, poderíamos ter uma versão assim:

#import "Nave.h"

@implementation Nave

@synthesize velocidade = _velocidade;

- (void) orbitarNave:(Planeta *) planeta naAltitude:(double)km {
    
}

- (void) setVelocidade:(int)velocidade {
    if (velocidade < 0) {
        velocidade = 0;
    }
    _velocidade = velocidade;
}


@end

O método get permanece sendo gerado, mas o método set usado vai ser o que foi definido manualmente.

Vamos ficar por aqui. No próximo post mostraremos como fazer chamadas de métodos usando a linguagem Objective-C.

Até lá.

quarta-feira, 11 de dezembro de 2013

Objective-C

Vamos dividir o tópico da linguagem usada no iOS, o Objective-C, em alguns post, uma vez que aprender uma linguagem requer mais do que umas poucas horas. Na realidade, este (e os outros) tem post tem como objetivo introduzir os conceitos da linguagem. Na sua totalidade, a linguagem Objective-C e suas APIs são bastante amplas.

Mas, vamos ao que interessa.

A linguagem Objective-C é derivada do C, usa o paradigma orientado a objetos e tem algumas coisas um pouco diferentes das linguagens de programação mais difundidas como Java e C#.

As classes Java são criadas em dois tipos de arquivos diferentes: o arquivo de definição (com extensão .h) e o arquivo de implementação (com extensão .m). Suponha que queremos definir uma classe Nave (espacial) que herda de uma classe Veiculo. A declaração do arquivo .h ficaria da seguinte forma:


// precisa importar o haader da classe pai
#import "Veiculo.h"

// declaração do nome da classe e da classe pai
@interface Nave : Veiculo

// definição do cabeçalho dos métodos

@end


O arquivo .m teria a seguinte definição:

// precisa importar a classe header
#import "Nave.h"

@implementation Nave

// implementação dos métodos declarados

@end


No arquivo de implementação é possível definir métodos que serão privados. Para isto devemos criar uma declaração @interface e finalizar com @end, como no exemplo abaixo:

#import "Nave.h"

@interface Nave()

// declaração de métodos privados

@end

@implementation Nave


@end

Vejamos a figura abaixo, na qual estamos definindo o seguinte método:

- (void) orbitarNave:(Planeta *) planeta naAltitude:(double)km;





Pode parecer estranho, mas o nome do método é orbitarNave:naAltitude. Como eu comentei antes, o Objective-C é bem diferente de outras linguagens, mas com o tempo acaba se acostumando. A implementação do método no arquivo .m fica da seguinte forma:

- (void) orbitarNave:(Planeta *) planeta naAltitude:(double)km {
    
    // implementação do método
    

}

Vou ficar por aqui para o post não ficar muito longo. No próximo vamos falar sobre atributos e métodos get e set.

Até a próxima!