Operador de ponto (“.”) E operador de seta (“->”) usam em C versus Objetivo-C

Estou tentando entender algumas das diferenças de uso e syntax em C versus Objective-C. Em particular, eu quero saber como (e por que) o uso difere para o operador de ponto e o operador de seta em C versus Objetivo-C. Aqui está um exemplo simples.

Código C:

// declare a pointer to a Fraction struct Fraction *frac; ... // reference an 'instance' variable int n = (*frac).numerator; // these two expressions int n = frac->numerator; // are equivalent 

Código Objetivo-C:

 // declare a pointer to a Fraction Fraction *frac = [[Fraction alloc] init]; ... // reference an instance variable int n = frac.numerator; // why isn't this (*frac).numerator or frac->numerator?? 

Então, vendo como o frac é o mesmo em ambos os programas (isto é, um ponteiro para um object ou estrutura Fraction), por que eles estão usando uma syntax diferente ao acessar propriedades? Em particular, em C, a propriedade numerator é acessada com frac->numerator , mas com Objective-C, ela é acessada usando o operador dot, com frac.numerator . Como frac é um ponteiro em ambos os programas, por que essas expressões são diferentes? Alguém pode ajudar a esclarecer isso para mim?

frac na verdade não é o mesmo em ambos os programas.

A Fraction AC é uma struct , que é um tipo de base sem operadores sobrecarregados e só pode ser realmente construída e destruída por padrão. Se você definir funções ou campos na estrutura, a maneira de acessar essas propriedades em C é com o operador de ponto ( . ). Objective-C mantém este operador quando você usa struct s. Por conveniência, você pode executar uma operação de remoção de ponto e ponto usando o operador de seta ( -> ) (as duas expressões equivalentes mencionadas). O Objective-C também preserva isso ao acessar struct .

Uma Fraction Objective-C no seu exemplo, no entanto, é provavelmente (supõe-se) um ponteiro de pelo menos tipo id , que é simplesmente um nome de class e um ponteiro para a instância daquela class sob o capô. Também é muito provável que seja uma subclass de NSObject ou NSProxy . Essas classs Objective-C são especiais, pois possuem uma camada inteira de operações predefinidas sobre apenas uma estrutura C (se você realmente quer escavar nela, então você pode dar uma olhada na Referência de Tempo de Execução do Objective-C ). Também é importante notar que uma class Objective-C é sempre um ponteiro .

Uma das operações mais básicas é objc_msgSend . Quando operamos nesses tipos de objects, o compilador Objective-C interpreta um operador de ponto ( . ) Ou a syntax de colchetes ( [object method] ) como uma chamada de método objc_msgSend . Para informações mais detalhadas sobre o que realmente acontece aqui, veja esta série de posts de Bill Bumgarner, um engenheiro da Apple que supervisiona o desenvolvimento do tempo de execução Obj-C.

O operador de seta ( -> ) não deve ser usado em objects Objective-C. Como eu disse, as instâncias de class Objective-C são uma estrutura C com uma camada extra de comunicação adicionada, mas essa camada de comunicação é essencialmente omitida quando você usa a seta. Por exemplo, se você abrir o Xcode e digitar [UIApplication sharedApplication]-> e, em seguida, exibir a lista de conclusão do método, verá o seguinte:

Uma lista de ivars internos em um objeto Obj-C ao usar o operador de seta

Aqui você pode ver um monte de campos normais que geralmente [[UIApplication sharedApplication] delegate] com a syntax de colchetes (como [[UIApplication sharedApplication] delegate] ). Esses itens específicos, no entanto, são os campos C que armazenam os valores de suas respectivas propriedades Objective-C.

Então, você pode pensar mais ou menos assim:

Operador de ponto em um object C

  1. (em tempo de execução) Valor de retorno do campo

Operador de seta em um object C (ponteiro)

  1. Ponteiro de referência
  2. Valor de retorno do campo

Operador de pontos / colchetes em um object Objective-C (ponteiro)

  1. (em tempo de compilation) Substituir por chamada para objc_msgSend
  2. (em tempo de execução) Procure a definição de class Obj-C, lance exceção se algo deu errado
  3. Ponteiro de referência
  4. Valor de retorno do campo

Operador de seta em um object Objective-C (ponteiro)

  1. (no tempo de execução) Ponteiro de referência
  2. Valor de retorno do campo

Agora estou simplificando demais aqui, mas para resumir: os operadores de flechas parecem fazer basicamente a mesma coisa em ambos os casos, mas o operador ponto tem um significado extra / diferente em Objective-C.

A notação de pontos é uma opção de design. Como sempre lidamos com pointers para instâncias objc, eu acho que os designers queriam algo familiar, que também não quebraria os programas existentes. Foi introduzido no ObjC 2 – apenas alguns anos atrás. Antes disso, você sempre precisava usar colchetes para enviar mensagens.

A notação de pontos faz diferença – não é access direto, mas uma mensagem .

Isso é:

 obj.property = val; // is the same as: [obj setProperty:val]; // and not: obj->property = val; val = obj.property; // is the same as: val = [obj property]; // and not: val = obj->property; 

Você ainda pode escrever obj->ivar para acessar um ponteiro para os membros do object (se visível).

No seu primeiro exemplo, a Fraction é uma estrutura. Em seu segundo exemplo, Fraction é uma class Objective-C (e no iOS provavelmente seria uma subclass de NSObject ).

C ++ não permite sobrecarga do operator . . Portanto, sem informações adicionais, você pode deduzir que a notação de ponto que você está vendo é uma construção de linguagem adicional integrada ao Objective-C, em vez de um operador definido ou sobrecarregado pelo C / C ++.

Quando isso acontece, a notação de ponto é simplesmente um recurso de design que os implementadores escolheram como atalho para o access à propriedade, totalmente equivalente ao getter de colchetes:

 myObjCVar.prop == [myObjCVar prop]; 

O operador ponto em objects é uma syntax especial para acessar as propriedades dos objects. Ele chama o getter ou setter da propriedade nos bastidores. Por exemplo, [@"hello" length] e @"hello".length são equivalentes *. Para todos os outros tipos, o ponto é o mesmo que o ponto C e a seta é sempre a mesma.

* Nota: O método do acessador nem sempre será nomeado da mesma forma que a propriedade. Se for uma propriedade declarada e a declaração designar um método getter ou setter especial, essa será usada em seu lugar.

As notações de ponto e flecha são igualmente as mesmas em C como em Objective-C (superconjunto estrito de). Eu acho que a diferença fundamental que precisa ser distinguida é a diferença entre uma estrutura e um object Objective-C.

A notação de ponto usada para objects no Objective-C é usada para propriedades que foram introduzidas no Objective-C 2.0. No entanto, com structs, a notação -> e ponto entre Objective-C e C são as mesmas.