Dominando Protocolos, Categorias e Blocos no Objective-C

Protocolos (Protocol)

Em Objective-C, os protocolos são utilizados para definir um contrato de métodos que outras classes podem adotar, estabelecendo um conjunto de comportamentos padronizados. Diferente de algumas linguagens orientadas a objetos que utilizam a palavra-chave interface para este fim, no Objective-C o termo @interface é estritamente reservado para a declaração de classes. Para definir contratos, utilizamos a diretiva @protocol.

Abaixo, definimos um protocolo chamado DataProcessing e uma classe JSONParser que assume o compromisso de implementar seus métodos.

// DataProcessing.h
#import <Foundation/Foundation.h>

@protocol DataProcessing <NSObject>
- (void)processData:(NSString *)data;
@end

// JSONParser.h
#import <Foundation/Foundation.h>
#import "DataProcessing.h"

@interface JSONParser : NSObject <DataProcessing>
@end

// JSONParser.m
#import "JSONParser.h"

@implementation JSONParser

- (void)processData:(NSString *)data {
    NSLog(@"Processando payload de dados: %@", data);
}

@end

Categorias (Category)

Categorias são um recurso poderoso que permite adicionar novos métodos a uma classe existente sem a necessidade de criar uma subclasse ou alterar o código-fonte original. Isso é particularmente útil para estender classes nativas do framwork Foundation. Por exemplo, podemos criar uma extensão para a classe NSString a fim de adicionar uma funcionalidade de inversão de texto.

// NSString+Reverse.h
#import <Foundation/Foundation.h>

@interface NSString (ReverseExtension)
- (NSString *)reversedString;
@end

// NSString+Reverse.m
#import "NSString+Reverse.h"

@implementation NSString (ReverseExtension)

- (NSString *)reversedString {
    NSMutableString *reversed = [NSMutableString stringWithCapacity:self.length];
    for (NSUInteger i = self.length; i > 0; i--) {
        [reversed appendFormat:@"%C", [self characterAtIndex:(i - 1)]];
    }
    return reversed;
}

@end

// main.m
#import <Foundation/Foundation.h>
#import "NSString+Reverse.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSString *originalText = @"Objective-C";
        NSLog(@"Texto original: %@", originalText);
        
        NSString *invertedText = [originalText reversedString];
        NSLog(@"Texto invertido: %@", invertedText);
    }
    return 0;
}

Blocos (Block)

Blocos representam a implementação de closures no Objective-C. Eles permitem que trechos de código sejam encapsulados, passados como argumentos, armazenados em variáveis e executados posteriormente. Isso é fundamental para operações assíncronas, callbacks e manipulação de coleções, funcionando de maneira similar aos delegados anônimos ou expressões lambda em outras linguagens.

A seguir, demonstramos o uso de um bloco para gerenciar o callback de uma tarefa assíncrona simulada.

// TaskManager.h
#import <Foundation/Foundation.h>

typedef void (^CompletionHandler)(NSString *result, NSError *error);

@interface TaskManager : NSObject
- (void)executeTaskWithCompletion:(CompletionHandler)handler;
@end

// TaskManager.m
#import "TaskManager.h"

@implementation TaskManager

- (void)executeTaskWithCompletion:(CompletionHandler)handler {
    // Simulação de processamento assíncrono
    NSString *mockResult = @"Dados processados com sucesso";
    if (handler) {
        handler(mockResult, nil);
    }
}

@end

// main.m
#import <Foundation/Foundation.h>
#import "TaskManager.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        TaskManager *manager = [[TaskManager alloc] init];

        [manager executeTaskWithCompletion:^(NSString *result, NSError *error) {
            if (error) {
                NSLog(@"Falha na execução: %@", error.localizedDescription);
            } else {
                NSLog(@"Sucesso: %@", result);
            }
        }];
    }
    return 0;
}

Ao trabalhar com blocos, é essencial compreender as seguintes regras de sintaxe e comportamento:

  • Declaração de Tipo: A estrutura básica é TipoDeRetorno (^nomeDaVariavel)(ListaDeParametros).
  • Uso de typedef: Para melhorar a legibilidade, recomenda-se definir tipos personalizados para blocos complexos, como em typedef void (^CompletionHandler)(NSString *, NSError *);.
  • Implementação: A sintaxe para instanciar o bloco é ^(ListaDeParametros) { corpo do bloco }.
  • Captura de Variáveis: Blocos podem ler variáveis definidas em seu escopo externo. No entanto, para modificar o valor de uma variável externa, é obrigatório declará-la utilizando o modificador __block.

Tags: Objective-C protocol category block closures

Publicado em 8-29 01:27