Objective-C 在 iOS 开发中的基础应用
一、Objective-C 基础语法
1.1 变量与数据类型
Objective-C 支持多种基本数据类型,如整数、浮点数、字符和布尔值。
- 整数类型:
int
用于表示整数,例如int age = 25;
。此外,还有short
(短整型)、long
(长整型)等,根据不同平台,它们的字节数可能有所不同。NSInteger
是一个根据平台自动适配的整数类型,在 32 位系统上等价于int
,在 64 位系统上等价于long
。例如:
NSInteger num = 100;
- 浮点数类型:
float
表示单精度浮点数,double
表示双精度浮点数。float
精度相对较低,double
精度更高且更常用。例如:
float piFloat = 3.14159f; // 注意单精度浮点数需要在数字后加 f
double piDouble = 3.141592653589793;
- 字符类型:
char
用于表示单个字符,如char grade = 'A';
。Objective-C 还引入了unichar
类型,用于表示 Unicode 字符,在处理国际化字符时很有用。例如:
unichar chineseChar = '\u4e2d'; // 表示汉字 “中”
- 布尔类型:
BOOL
是 Objective-C 中的布尔类型,它只有两个值:YES
和NO
。例如:
BOOL isDone = YES;
1.2 运算符
Objective-C 拥有丰富的运算符,包括算术运算符、比较运算符、逻辑运算符等。
- 算术运算符:
+
(加)、-
(减)、*
(乘)、/
(除)、%
(取余)。例如:
int a = 10;
int b = 3;
int sum = a + b; // sum 为 13
int quotient = a / b; // quotient 为 3
int remainder = a % b; // remainder 为 1
- 比较运算符:
==
(等于)、!=
(不等于)、>
(大于)、<
(小于)、>=
(大于等于)、<=
(小于等于)。比较运算符返回BOOL
值。例如:
int num1 = 5;
int num2 = 10;
BOOL isGreater = num1 > num2; // isGreater 为 NO
BOOL isEqual = num1 == num2; // isEqual 为 NO
- 逻辑运算符:
&&
(逻辑与)、||
(逻辑或)、!
(逻辑非)。逻辑运算符用于组合多个条件。例如:
BOOL condition1 = YES;
BOOL condition2 = NO;
BOOL resultAnd = condition1 && condition2; // resultAnd 为 NO
BOOL resultOr = condition1 || condition2; // resultOr 为 YES
BOOL resultNot =!condition1; // resultNot 为 NO
- 赋值运算符:
=
用于赋值,同时还有复合赋值运算符,如+=
、-=
、*=
、/=
等。例如:
int value = 5;
value += 3; // 等价于 value = value + 3,此时 value 为 8
1.3 控制语句
Objective-C 提供了常见的控制语句,如 if - else
、switch - case
、for
、while
和 do - while
。
if - else
语句:根据条件执行不同的代码块。例如:
int score = 85;
if (score >= 90) {
NSLog(@"优秀");
} else if (score >= 80) {
NSLog(@"良好");
} else {
NSLog(@"需努力");
}
switch - case
语句:用于多分支选择,根据一个整数表达式的值来选择执行不同的分支。例如:
int day = 3;
switch (day) {
case 1:
NSLog(@"星期一");
break;
case 2:
NSLog(@"星期二");
break;
case 3:
NSLog(@"星期三");
break;
default:
NSLog(@"其他");
break;
}
for
循环:用于已知循环次数的情况。例如:
for (int i = 0; i < 5; i++) {
NSLog(@"%d", i);
}
while
循环:在条件为真时重复执行代码块,先判断条件再执行。例如:
int count = 0;
while (count < 3) {
NSLog(@"%d", count);
count++;
}
do - while
循环:先执行一次代码块,然后再根据条件判断是否继续循环。例如:
int num = 0;
do {
NSLog(@"%d", num);
num++;
} while (num < 3);
二、Objective-C 面向对象编程
2.1 类与对象
在 Objective-C 中,类是对象的蓝图,对象是类的实例。
- 定义类:使用
@interface
和@implementation
关键字。例如,定义一个简单的Person
类:
@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) NSInteger age;
- (void)sayHello;
@end
@implementation Person
- (void)sayHello {
NSLog(@"大家好,我叫 %@,今年 %ld 岁", self.name, (long)self.age);
}
@end
- 创建对象:使用
[[类名 alloc] init]
方式创建对象。例如:
Person *person = [[Person alloc] init];
person.name = @"张三";
person.age = 30;
[person sayHello];
2.2 继承
继承允许一个类从另一个类获取属性和方法。例如,定义一个 Student
类继承自 Person
类:
@interface Student : Person
@property (nonatomic, strong) NSString *school;
- (void)study;
@end
@implementation Student
- (void)study {
NSLog(@"%@ 在 %@ 学习", self.name, self.school);
}
@end
然后可以创建 Student
对象并使用其继承和自身的方法:
Student *student = [[Student alloc] init];
student.name = @"李四";
student.age = 20;
student.school = @"某大学";
[student sayHello];
[student study];
2.3 封装
封装通过访问控制来隐藏对象的内部细节。Objective-C 使用 @private
、@protected
和 @public
关键字。
@private
:成员变量只能在类的实现文件中访问。例如:
@interface Example : NSObject
{
@private
int privateVar;
}
@end
@implementation Example
- (void)setPrivateVar:(int)value {
privateVar = value;
}
- (int)getPrivateVar {
return privateVar;
}
@end
@protected
:成员变量在类及其子类中可访问。这是默认的访问级别,如果不指定访问控制关键字,成员变量默认为@protected
。@public
:成员变量在任何地方都可访问,但通常不推荐广泛使用,因为它破坏了封装性。
2.4 多态
多态允许通过基类的指针或引用来调用子类的方法。例如,定义一个 Animal
类及其子类 Dog
和 Cat
:
@interface Animal : NSObject
- (void)makeSound;
@end
@implementation Animal
- (void)makeSound {
NSLog(@"动物发出声音");
}
@end
@interface Dog : Animal
- (void)makeSound {
NSLog(@"汪汪汪");
}
@end
@interface Cat : Animal
- (void)makeSound {
NSLog(@"喵喵喵");
}
@end
然后可以通过 Animal
类型的变量来调用不同子类的 makeSound
方法:
Animal *animal1 = [[Dog alloc] init];
Animal *animal2 = [[Cat alloc] init];
[animal1 makeSound]; // 输出 “汪汪汪”
[animal2 makeSound]; // 输出 “喵喵喵”
三、内存管理
3.1 引用计数原理
Objective-C 使用引用计数(Reference Counting)来管理内存。每个对象都有一个引用计数,当对象被创建时,引用计数为 1。每次有新的指针指向该对象,引用计数加 1;当指针不再指向该对象,引用计数减 1。当引用计数为 0 时,对象的内存被释放。例如:
NSString *str1 = @"Hello"; // str1 引用计数为 1
NSString *str2 = str1; // str1 引用计数加 1,变为 2
str1 = nil; // str1 不再指向对象,对象引用计数减 1,变为 1
str2 = nil; // str2 不再指向对象,对象引用计数减 1,变为 0,对象内存被释放
3.2 自动释放池(Autorelease Pool)
自动释放池用于延迟释放对象。当对象发送 autorelease
消息时,它被放入最近的自动释放池中。当自动释放池被销毁时,池中的所有对象都会收到 release
消息。例如:
@autoreleasepool {
NSString *tempStr = [[NSString alloc] initWithFormat:@"临时字符串"];
[tempStr autorelease];
// 这里 tempStr 不会立即释放,而是在自动释放池销毁时释放
}
// 自动释放池销毁,tempStr 收到 release 消息,若引用计数变为 0 则释放内存
3.3 ARC(自动引用计数)
ARC 是 Xcode 4.2 引入的功能,它自动管理对象的内存。在 ARC 环境下,编译器会自动插入 retain
、release
和 autorelease
等代码。例如:
// ARC 环境下
NSString *newStr = [[NSString alloc] initWithFormat:@"ARC 字符串"];
// 无需手动释放 newStr,ARC 会在适当时候处理
但在 ARC 下也有一些注意事项,比如不能直接调用 retain
、release
和 autorelease
方法。如果需要手动管理内存,可以使用 __weak
、__strong
等修饰符。__strong
是默认的修饰符,表示强引用,会增加对象的引用计数。__weak
表示弱引用,不会增加对象的引用计数,当对象被释放时,指向它的弱引用指针会自动被设为 nil
,从而避免野指针。例如:
__strong NSString *strongStr = [[NSString alloc] initWithFormat:@"强引用字符串"];
__weak NSString *weakStr = strongStr;
strongStr = nil;
// 此时 strongStr 不再指向对象,对象引用计数减 1 可能被释放
// weakStr 自动变为 nil,不会成为野指针
四、Objective-C 在 iOS 界面开发中的应用
4.1 UIKit 框架基础
UIKit 是 iOS 开发中用于构建用户界面的框架。它包含了各种视图(UIView
)和视图控制器(UIViewController
)。
UIView
:是所有视图的基类,用于显示内容和响应用户交互。例如,创建一个简单的红色矩形视图:
UIView *redView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 200, 150)];
redView.backgroundColor = [UIColor redColor];
[self.view addSubview:redView];
UIViewController
:用于管理视图层次结构和处理用户交互逻辑。例如,创建一个简单的视图控制器:
@interface MyViewController : UIViewController
@end
@implementation MyViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
}
@end
然后可以在应用的入口处将该视图控制器设置为窗口的根视图控制器:
MyViewController *myVC = [[MyViewController alloc] init];
self.window.rootViewController = myVC;
4.2 视图布局
iOS 提供了多种视图布局方式,如自动布局(Auto Layout)和手动布局。
- 手动布局:通过设置视图的
frame
属性来确定其位置和大小。例如:
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(50, 50, 200, 30)];
label.text = @"手动布局的标签";
[self.view addSubview:label];
- 自动布局:使用约束(
NSLayoutConstraint
)来定义视图之间的关系。例如,将一个按钮水平居中并距离顶部 100 像素:
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
[button setTitle:@"自动布局按钮" forState:UIControlStateNormal];
[self.view addSubview:button];
[button.translatesAutoresizingMaskIntoConstraints setValue:@NO];
NSLayoutConstraint *centerXConstraint = [NSLayoutConstraint constraintWithItem:button
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0];
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:button
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:100];
[self.view addConstraints:@[centerXConstraint, topConstraint]];
4.3 控件使用
iOS 提供了丰富的控件,如按钮(UIButton
)、文本框(UITextField
)、标签(UILabel
)等。
UIButton
:用于触发操作。例如,为按钮添加点击事件:
UIButton *actionButton = [UIButton buttonWithType:UIButtonTypeSystem];
[actionButton setTitle:@"点击我" forState:UIControlStateNormal];
[actionButton addTarget:self action:@selector(buttonTapped) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:actionButton];
// 实现 buttonTapped 方法
- (void)buttonTapped {
NSLog(@"按钮被点击了");
}
UITextField
:用于用户输入文本。例如,监听文本框的文本变化:
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(50, 150, 200, 30)];
textField.borderStyle = UITextBorderStyleRoundedRect;
[textField addTarget:self action:@selector(textChanged:) forControlEvents:UIControlEventEditingChanged];
[self.view addSubview:textField];
// 实现 textChanged 方法
- (void)textChanged:(UITextField *)textField {
NSLog(@"文本内容变为: %@", textField.text);
}
UILabel
:用于显示文本。例如,设置标签的文本和字体:
UILabel *infoLabel = [[UILabel alloc] initWithFrame:CGRectMake(50, 200, 200, 30)];
infoLabel.text = @"这是一个标签";
infoLabel.font = [UIFont systemFontOfSize:16];
[self.view addSubview:infoLabel];
五、数据存储
5.1 用户偏好设置(NSUserDefaults)
NSUserDefaults
用于存储简单的用户偏好数据,如应用的设置选项。例如,保存用户的用户名:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:@"user123" forKey:@"username"];
[defaults synchronize];
读取数据时:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *username = [defaults objectForKey:@"username"];
NSLog(@"用户名: %@", username);
5.2 文件存储
可以使用 NSFileManager
进行文件的创建、读取、写入等操作。例如,将一段文本写入文件:
NSString *text = @"这是要写入文件的内容";
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *fileName = [documentsPath stringByAppendingPathComponent:@"example.txt"];
NSError *error;
BOOL success = [text writeToFile:fileName atomically:YES encoding:NSUTF8StringEncoding error:&error];
if (success) {
NSLog(@"文件写入成功");
} else {
NSLog(@"文件写入失败: %@", error);
}
读取文件内容:
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *fileName = [documentsPath stringByAppendingPathComponent:@"example.txt"];
NSString *content = [NSString stringWithContentsOfFile:fileName encoding:NSUTF8StringEncoding error:nil];
NSLog(@"文件内容: %@", content);
5.3 SQLite 数据库
SQLite 是一个轻量级的嵌入式数据库,在 iOS 开发中可用于存储结构化数据。首先要导入 SQLite 库,然后使用 sqlite3
相关函数进行操作。例如,创建一个数据库表并插入数据:
#import <sqlite3.h>
sqlite3 *database;
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *databasePath = [documentsPath stringByAppendingPathComponent:@"test.db"];
if (sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
const char *createTableSQL = "CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER)";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, createTableSQL, -1, &statement, nil) == SQLITE_OK) {
if (sqlite3_step(statement) == SQLITE_DONE) {
NSLog(@"表创建成功");
} else {
NSLog(@"表创建失败");
}
sqlite3_finalize(statement);
}
const char *insertSQL = "INSERT INTO users (name, age) VALUES (?,?)";
if (sqlite3_prepare_v2(database, insertSQL, -1, &statement, nil) == SQLITE_OK) {
sqlite3_bind_text(statement, 1, "张三", -1, SQLITE_TRANSIENT);
sqlite3_bind_int(statement, 2, 30);
if (sqlite3_step(statement) == SQLITE_DONE) {
NSLog(@"数据插入成功");
} else {
NSLog(@"数据插入失败");
}
sqlite3_finalize(statement);
}
sqlite3_close(database);
} else {
NSLog(@"数据库打开失败");
}
查询数据:
sqlite3 *database;
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *databasePath = [documentsPath stringByAppendingPathComponent:@"test.db"];
if (sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
const char *selectSQL = "SELECT * FROM users";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, selectSQL, -1, &statement, nil) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
int id = sqlite3_column_int(statement, 0);
const char *nameChars = (const char *)sqlite3_column_text(statement, 1);
NSString *name = [NSString stringWithUTF8String:nameChars];
int age = sqlite3_column_int(statement, 2);
NSLog(@"ID: %d, 姓名: %@, 年龄: %d", id, name, age);
}
sqlite3_finalize(statement);
}
sqlite3_close(database);
} else {
NSLog(@"数据库打开失败");
}
通过以上内容,我们详细介绍了 Objective-C 在 iOS 开发中的基础应用,从基础语法到面向对象编程,再到内存管理、界面开发和数据存储等方面,希望能帮助开发者更好地掌握 Objective-C 进行 iOS 应用开发。