MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Objective-C基础语法与数据类型详解

2023-12-143.2k 阅读

一、Objective-C 概述

Objective-C 是一种通用、高级、面向对象的编程语言,它扩展了标准的 ANSI C 语言,加入了面向对象编程的特性。Objective-C 是 macOS 和 iOS 开发的主要编程语言,被广泛应用于苹果生态系统中的应用程序开发。

它具有动态运行时的特性,允许在运行时决定对象的类和方法调用,这使得代码更加灵活和强大。Objective-C 与 C 语言的紧密结合意味着开发者可以在需要时使用 C 语言的底层功能,同时享受面向对象编程带来的便利。

二、基础语法

(一)文件结构

在 Objective-C 中,源文件通常分为两类:.h(头文件)和.m(实现文件)。头文件用于声明类、方法和变量,而实现文件则用于定义这些声明的具体实现。

例如,定义一个简单的Person类,Person.h文件内容如下:

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) NSInteger age;

- (void)sayHello;

@end

在上述代码中,#import <Foundation/Foundation.h>导入了 Foundation 框架,这是 Objective-C 开发中非常重要的一个框架,提供了基本的数据类型、集合类等。@interface声明了一个Person类,它继承自NSObjectNSObject是 Objective-C 中所有类的基类。@property声明了两个属性,nameage,分别表示人的名字和年龄。- (void)sayHello;声明了一个实例方法sayHello

Person.m文件内容如下:

#import "Person.h"

@implementation Person

- (void)sayHello {
    NSLog(@"Hello, my name is %@ and I'm %ld years old.", self.name, (long)self.age);
}

@end

Person.m文件中,@implementation实现了Person类,- (void)sayHello方法的具体实现中,使用NSLog函数打印出人的名字和年龄。NSLog类似于 C 语言中的printf,但它会自动添加时间戳和换行符,方便调试。

(二)注释

Objective-C 支持 C 语言风格的注释,包括单行注释和多行注释。

  1. 单行注释:以//开头,直到行末。
// 这是一个单行注释,用于解释下面这行代码的作用
NSInteger number = 10;
  1. 多行注释:以/*开头,以*/结尾,可以跨多行。
/*
这是一个多行注释,
可以用于解释一段代码块的功能。
例如下面这个循环的作用是打印 1 到 10 的数字。
*/
for (NSInteger i = 1; i <= 10; i++) {
    NSLog(@"%ld", (long)i);
}

(三)语句和表达式

  1. 表达式:由操作数和运算符组成,例如2 + 3就是一个表达式,它返回值 5。Objective-C 支持 C 语言中的大部分运算符,如算术运算符(+-*/)、比较运算符(==!=<>)、逻辑运算符(&&||!)等。
NSInteger result = 5 * (3 + 2); // 先计算括号内的表达式 3 + 2,再乘以 5,结果为 25
  1. 语句:语句是执行特定操作的代码单元。常见的语句包括赋值语句、控制语句等。
// 赋值语句
NSInteger num = 10;

// if - else 控制语句
if (num > 5) {
    NSLog(@"The number is greater than 5");
} else {
    NSLog(@"The number is less than or equal to 5");
}

(四)控制流

  1. if - else 语句:用于根据条件执行不同的代码块。
NSInteger score = 85;
if (score >= 90) {
    NSLog(@"Grade: A");
} else if (score >= 80) {
    NSLog(@"Grade: B");
} else {
    NSLog(@"Grade: C or below");
}
  1. switch - case 语句:用于根据一个表达式的值执行不同的分支。
NSInteger day = 3;
switch (day) {
    case 1:
        NSLog(@"Monday");
        break;
    case 2:
        NSLog(@"Tuesday");
        break;
    case 3:
        NSLog(@"Wednesday");
        break;
    default:
        NSLog(@"Other day");
        break;
}
  1. for 循环:用于重复执行一段代码指定的次数。
for (NSInteger i = 0; i < 5; i++) {
    NSLog(@"Iteration %ld", (long)i);
}
  1. while 循环:只要条件为真,就重复执行代码块。
NSInteger count = 0;
while (count < 3) {
    NSLog(@"Count: %ld", (long)count);
    count++;
}
  1. do - while 循环:先执行一次代码块,然后只要条件为真,就重复执行。
NSInteger value = 0;
do {
    NSLog(@"Value: %ld", (long)value);
    value++;
} while (value < 3);

三、数据类型

(一)基本数据类型

  1. 整数类型
    • char:通常用于表示单个字符,占用 1 个字节。在 Objective - C 中,它和 C 语言一样,可以用来存储字符的 ASCII 码值。
char ch = 'a';
NSLog(@"The character is %c", ch);
- **short**:短整型,占用 2 个字节,用于存储较小范围的整数。
short num1 = 100;
NSLog(@"Short number: %hd", num1);
- **int**:整型,通常占用 4 个字节,是最常用的整数类型。在 32 位系统和 64 位系统中,`int`的大小可能会有所不同,但现代编译器通常会根据系统架构进行优化。
int num2 = 12345;
NSLog(@"Integer number: %d", num2);
- **long**:长整型,占用 8 个字节,用于存储较大范围的整数。
long num3 = 123456789012345L;
NSLog(@"Long number: %ld", num3);
- **NSInteger**:这是一个平台相关的整数类型,在 32 位系统中,它等同于`int`,在 64 位系统中,它等同于`long`。在 iOS 和 macOS 开发中,推荐使用`NSInteger`来处理整数,以确保代码在不同平台上的兼容性。
NSInteger num4 = 987654321;
NSLog(@"NSInteger number: %ld", (long)num4);
  1. 浮点类型
    • float:单精度浮点型,占用 4 个字节,用于存储小数。它的精度大约为 6 - 7 位有效数字。
float f1 = 3.14159f;
NSLog(@"Float number: %f", f1);
- **double**:双精度浮点型,占用 8 个字节,精度更高,大约为 15 - 17 位有效数字。在处理需要高精度的小数运算时,通常使用`double`。
double d1 = 3.141592653589793;
NSLog(@"Double number: %lf", d1);
  1. 布尔类型
    • BOOL:在 Objective - C 中,BOOL是用于表示布尔值的类型,它实际上是一个char类型的别名。YES表示真,NO表示假。
BOOL isDone = YES;
if (isDone) {
    NSLog(@"The task is done.");
} else {
    NSLog(@"The task is not done yet.");
}

(二)枚举类型

枚举类型是一种用户自定义的数据类型,用于定义一组命名的常量。它通过enum关键字来定义。

enum Weekday {
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday
};

// 使用枚举类型
enum Weekday today = Wednesday;
NSLog(@"Today is %ld", (long)today);

在上述代码中,定义了一个Weekday枚举类型,其中每个枚举常量都有一个默认的整数值,从 0 开始依次递增。可以通过赋值给变量来使用枚举类型。

也可以显式指定枚举常量的值:

enum Month {
    January = 1,
    February,
    March,
    April,
    May,
    June,
    July,
    August,
    September,
    October,
    November,
    December
};

enum Month currentMonth = June;
NSLog(@"Current month is %ld", (long)currentMonth);

(三)结构体类型

结构体是一种可以将不同类型的数据组合在一起的数据结构。通过struct关键字定义。

struct Point {
    NSInteger x;
    NSInteger y;
};

// 使用结构体
struct Point p1;
p1.x = 10;
p1.y = 20;
NSLog(@"Point coordinates: (%ld, %ld)", (long)p1.x, (long)p1.y);

也可以在定义结构体的同时声明结构体变量:

struct Rectangle {
    NSInteger width;
    NSInteger height;
} rect1;

rect1.width = 100;
rect1.height = 200;
NSLog(@"Rectangle dimensions: width = %ld, height = %ld", (long)rect1.width, (long)rect1.height);

(四)指针类型

指针是一种存储变量地址的数据类型。在 Objective - C 中,指针的使用和 C 语言类似。

  1. 基本数据类型指针
NSInteger num = 10;
NSInteger *ptr = &num; // 指针 ptr 指向 num 的地址
NSLog(@"The value of num is %ld", (long)*ptr); // 通过指针访问 num 的值
  1. 结构体指针
struct Point {
    NSInteger x;
    NSInteger y;
};

struct Point p1 = {10, 20};
struct Point *pPtr = &p1;
NSLog(@"Point coordinates: (%ld, %ld)", (long)pPtr->x, (long)pPtr->y);

在上述代码中,pPtr->x(*pPtr).x是等价的,表示通过指针访问结构体成员。

(五)对象类型

  1. NSObjectNSObject是 Objective - C 中所有类的基类,它定义了一些基本的方法,如内存管理方法(allocinit等)和对象比较方法(isEqual:等)。
  2. NSString:用于表示字符串,是 Objective - C 中常用的类之一。NSString对象是不可变的,一旦创建,其内容不能被修改。
NSString *str1 = @"Hello, World!";
NSLog(@"String: %@", str1);

// 字符串拼接
NSString *str2 = [str1 stringByAppendingString:@" How are you?"];
NSLog(@"New string: %@", str2);
  1. NSMutableStringNSMutableStringNSString的可变版本,可以在运行时修改字符串的内容。
NSMutableString *mutableStr = [NSMutableString stringWithString:@"Initial string"];
[mutableStr appendString:@" - modified"];
NSLog(@"Mutable string: %@", mutableStr);
  1. NSArray:用于存储一组有序的对象,NSArray对象是不可变的,即一旦创建,不能添加或删除元素。
NSArray *array1 = @[@"Apple", @10, @YES];
NSLog(@"Array: %@", array1);

// 获取数组元素
NSString *firstElement = array1[0];
NSLog(@"First element: %@", firstElement);
  1. NSMutableArrayNSMutableArrayNSArray的可变版本,可以动态地添加、删除和修改元素。
NSMutableArray *mutableArray = [NSMutableArray arrayWithObjects:@"One", @"Two", nil];
[mutableArray addObject:@"Three"];
NSLog(@"Mutable array: %@", mutableArray);

// 删除元素
[mutableArray removeObjectAtIndex:1];
NSLog(@"Modified mutable array: %@", mutableArray);
  1. NSDictionary:用于存储键值对,NSDictionary对象是不可变的。
NSDictionary *dict1 = @{@"name": @"John", @"age": @30};
NSLog(@"Dictionary: %@", dict1);

// 获取字典值
NSString *name = dict1[@"name"];
NSLog(@"Name: %@", name);
  1. NSMutableDictionaryNSMutableDictionaryNSDictionary的可变版本,可以在运行时添加、删除和修改键值对。
NSMutableDictionary *mutableDict = [NSMutableDictionary dictionaryWithObject:@"Jane" forKey:@"name"];
[mutableDict setObject:@25 forKey:@"age"];
NSLog(@"Mutable dictionary: %@", mutableDict);

// 删除键值对
[mutableDict removeObjectForKey:@"age"];
NSLog(@"Modified mutable dictionary: %@", mutableDict);

四、类型转换

  1. 自动类型转换:当不同类型的数据进行运算时,Objective - C 会自动进行类型转换,将低精度类型转换为高精度类型。
NSInteger num1 = 10;
double num2 = 3.14;
double result = num1 + num2; // num1 会自动转换为 double 类型
NSLog(@"Result: %lf", result);
  1. 强制类型转换:通过在表达式前加上目标类型,将一种类型的数据转换为另一种类型。
double d1 = 5.67;
NSInteger i1 = (NSInteger)d1; // 将 double 类型转换为 NSInteger 类型,小数部分会被截断
NSLog(@"Converted integer: %ld", (long)i1);

五、内存管理

在 Objective - C 中,内存管理至关重要。早期,开发者需要手动管理内存,通过alloc分配内存,release释放内存,retain增加对象的引用计数等。随着 ARC(自动引用计数)的引入,大部分内存管理工作由编译器自动完成。

  1. 手动内存管理
// 创建一个 NSString 对象
NSString *str = [[NSString alloc] initWithString:@"Manual memory management"];
// 使用对象
NSLog(@"String: %@", str);
// 释放对象
[str release];
  1. ARC 在 ARC 模式下,编译器会自动插入内存管理代码,开发者无需手动调用release等方法。
NSString *str2 = [[NSString alloc] initWithString:@"ARC memory management"];
NSLog(@"String with ARC: %@", str2);
// 无需手动释放,ARC 会自动处理

六、总结

Objective - C 的基础语法和数据类型是进行 iOS 和 macOS 开发的基石。掌握这些知识,开发者可以编写高效、健壮的代码。从基本的变量声明、数据类型使用,到复杂的对象操作和内存管理,每一个环节都需要深入理解和熟练运用。随着技术的发展,虽然 Swift 逐渐崭露头角,但 Objective - C 仍然在许多遗留项目和特定领域有着重要的地位,对于深入理解苹果生态系统的开发原理,学习 Objective - C 依然具有重要意义。