Objective-C 基础入门(一)
目录
一、什么是Objective-C?
Hello world
Tips:
二、Objective-C的类
1.新建一个OC类
self 指针
Tips:
2.NSString
创建实例
NSString方法
3.NSArray
创建数组
遍历数组
NSMutableArray
4.属性
声明属性
属性的特性
5.继承
创建
覆盖方法
super
继承层次
6.类扩展
7.循环引用与内存泄露
弱引用
一、什么是Objective-C?
- 是扩充C的面向对象的编程语言;OC可以完全兼容C语言,在OC中可以随便写C代码,甚至部分的C++代码。(其他类似的面向对象编程语言:C ——> C++;Objective-C;C #)
- Objective-C用来可发 Mac OS X 平台与 iOS 平台的应用程序
Hello world
#import
//类比#include<> <>引用的是系统库;""引用自己定义的类int main(int argc,const char * argv[])
{@autoreleasepool{//自动释放池NSLog(@"Hello World!");}return 0;
}
Tips:
- 输出语句 NSLog ( @"Hello World!" ); NSLog 是自动换行的,即无需 ‘ \n ’!
- command + R 运行;command + B 编译
二、Objective-C的类
1.新建一个OC类
- 新建一个类时会自动创建.h 与.m 两个文件,其中.h文件只包含声明不实现;.m文件实现声明的方法。
- 创建语句:
Person *per = [[Person alloc]init];
Person *per = [Person new];
BNRStockHolding.h
#import@interface BNRStockHolding:NSObject
{float _purchaseSharePrice;float _currentSharePrice;int _numberOfShares;
}-(void)setPurchaseSharePrice:(float)p setCurrentSharePrice:(float)c... setNumberOfShares:(int)n;-(float)costInDollars;
-(float)valueInDollars;@endBNRStockHolding.m:
#import"BNRStockHolding.h"@implementation BNRStockHolding-(void)setPurchaseSharePrice:(float)p setCurrentSharePrice:(float)c...setNumberOfShares:(int)n
{_purchaseSharePrice=p;_currentSharePrice=c;_numberOfShares=n;
}-(float)costInDollars
{return _purchaseSharePrice*_numberOfShares;
}
-(float)valueInDollars
{return _currentSharePrice*_numberOfShares;
}@endmain函数:
#import
#import "BNRStockHolding.h"int main ()
{
@autoreleasepool{printf("My StockHolding:\n");NSMutableArray *list=[[NSMutableArray alloc] init];BNRStockHolding *A=[[BNRStockHolding alloc] init];BNRStockHolding *B=[[BNRStockHolding alloc] init];BNRStockHolding *C=[[BNRStockHolding alloc] init];[A setPurchaseSharePrice:12 setCurrentSharePrice:14.5 setNumberOfShares:32];[B setPurchaseSharePrice:17 setCurrentSharePrice:12.3 setNumberOfShares:25];[C setPurchaseSharePrice:32 setCurrentSharePrice:27.5 setNumberOfShares:43];[list addObject:A];[list addObject:B];[list addObject:C];int i=1;for(BNRStockHolding *t in list)NSLog(@"第 %d 支股票的购入价为 %.2f,市值为 %.2f。",i++,[t costInDollars],[t valueInDollars]);}return 0;
}
头文件以 @interface 开始,以 @end 结束。注意要在花括号中声明成员变量。
- 实例变量
- 变量属性默认相当于 C++ 中的 private,只能通过实例方法进行存取。
- 变量命名以 _ 开头(后续会提到带 _ 的为实参,不带 _ 的为形参)。
- 实例(对象)方法(区别于类方法)命名规则:
- 以 - 号开头,所有数据类型写在()中
- 函数名与参数列表之间用:连接
- - ( 返回值类型 ) 函数名 : (参数类型) 参数名
- 调用格式 [ 对象指针 函数名 : 参数 ]
self 指针
相当于 C++ 中的 this 指针,可以在类的方法中调用对象自身的方法;还可以将 self 做为实参传递给其他方法,以便其访问“当前的”对象。例如:
-(void)addYourselfToArray:(NSMutableArray*)theArray
{[theArray addObject:self];
}
Tips:
- 不能丢掉:NSObject ,绝大部分类的基类都是 NSObject,它实现了引用计数的内存管理模型。
- 只有函数实现没有函数声明可以运行,但这是Objective-C的弱语法,不推荐使用。
- @autoreleasepool 自动释放池:作用是在运行时延迟释放,系统自动跟踪每个对象的使用情况,并在释放AutoreleasePool时,释放池中的全部对象。在正常情况下,创建的变量会在超出其作用域的时候release,但是如果将变量加入AutoreleasePool,那么release将延迟执行。
- Objective-C 没有命名空间,所以最好为类名加上特殊前缀,避免命名冲突。
2.NSString
创建实例
创建一个 NSString 字符串常量实例:
NSString *lament = @"Why me!";
用变量创建一个字符串实例:
NSString *dateString = [NSString stringWithFormat:@"The date is %@",now];
stringWithFormat:方法后面跟着一个格式字符串作为参数,这个格式字符串带有一个变量,变量的值类似与NSLog一样替换格式说明符。
NSString方法
- -(NSUInteger)length 返回字符串的长度,包括空格
NSUInterger charCount = [dateString length];
- -(BOOL)isEqualToString:(NSString *)other 查看一个字符串是否和另一个字符串相等
if([A isEqualToString:B])NSLog(@"%@ and %@ are equal.",A,B);
- -(NSString *)uppercaseString 将字符串变成大写形式
NSString *A = @"That makes me so happy!";
NSString *B =[A uppercaseString];
- -(NSRange)rangeOfString:(NSString*)s 查找字符及子字符串
NSString listOfNames = @"..." //名单
NSString name = @"Ward";
NSRange match = [listOfNames rangeOfString:name];
if(match.location == NSNotFound)NSLog(@"No match found!");
elseNSLog(@"Match!");
返回值 NSRange 是一个结构,包含 location 和 length 两个值。如果找不到目标子字符串则返回 NSNotFound。
3.NSArray
创建数组
与 NSString 相似,NSArray 也可以用字面常量语法创建实例。数组的内容写在方括号里,使用逗号分隔,前方带有@符号。
NSArray *dateList = @[now,tomorrow,yesterday];
NSArray 的实例是无法改变的,一旦 NSArray 实例被创建后,就无法添加或删除数组里的元素,也无法改变数组元素的顺序。
遍历数组
for(int i=0;i<[dateList count];i++)
{NSLog(@" %@",dateList[i]);
}
Objective-C 提供一种简化的 for 循环语法,称为快速枚举。省去了对数组计数的同时,高效地遍历数组的所有元素。
for(NSDate *d in dateList)
{NSLog(@"Here is a date: %@.",d);
}
类似于 C++ 中的 auto 遍历语法。
NSMutableArray
可以添加、删除或对元素重新进行排序。(NSMutableArray 是 NSArray 的子类)
NSMutableArray *dateList =[NSMutableArray array]; //创建空数组//将两个 NSDate 对象加入新创建的数组
[dateList addObject:now];
[dateList addObject:tomorrow];//将 yesterday 指针插入数组的起始位置
[dateList addObject:yesterday atIndex:0];//删除 yesterday 指针
[dateList removeObjectAtIndex:0];//快速遍历
for(NSDate *d in dateList)
{NSLog(@"Here is a date: %@.",d);
}
//在数组中查询是否有和 anObject 相等、相同的元素
-(NSUInteger) indexOfObject:(id) anObject;
-(NSUInteger) indexOfObjectIdenticalTo:(id) anObject;
创建:上述程序使用了 array 类方法来创建 NSMutableArray,等同于 [[NSMutableArray alloc] init];
添加:addObject :元素 方法自动在尾部添加元素,如果要将对象添加到一个特定的索引上,则可以使用 insertObject:atIndex:下标。
删除:removeObject:atIndex:下标 数组对象的计数也随之会减小。
遍历:不可在快速枚举过程中添加或者删除对象。
4.属性
声明属性
在自定义的类中删除实例变量,然后用两个属性重写存取方法的声明:
- 属性的声明以 @property 开始,然后是属性的类型和名称。
- 编译器会自动根据声明的属性声明与实现存取方法。
BNRStockHolding.h
#import
@interface BNRStockHolding:NSObject
@property (nonatomic) float purchaseSharePrice;
@property (nonatomic) float currentSharePrice;
@property (nonatomic) int numberOfShares;
{ float _purchaseSharePrice;
float _currentSharePrice;
int _numberOfShares;
}
-(void)setPurchaseSharePrice:(float)p setCurrentSharePrice:(float)c...
setNumberOfShares:(int)n;
-(float)costInDollars;
-(float)valueInDollars;
@end
.m文件中只需实现 costInDollars 与 valueInDollars 方法。
属性的特性
属性的特性会显示在 @property 后的括号中,属性第一可选项为
- 非原子性 nonatomic
- 原子性 atomic
与多线程有关,原子性保证多线程的安全;省略此选项时默认为原子属性。
属性的第二可选项为
- 只读 readonly
- 读写 readwrite
只读特性的值只能读取不能改写,编译器为其只生成取方法,不生成存方法;省略此选项时默认为读写属性。
使用属性标识的变量,在方法中使用到时,必须用 self.变量名
- 属性可以用点号调用存取方法
[mikey setWeightInKilos:96];
[mikey setHeightInMeters:1.8];
mikey.WeightInKilos = 96;
mikey.HerghtMeters = 1.8;
使用点调用的时候是在发送消息。
public 成员只能用 ->
5.继承
创建
#import "BNRPerson.h"
@interface BNREmployee:BNRPerson
@property (nonatomic) unsigned int employeeID;
@property (nonatomic) unsigned int officeAlarmCode;
@property (nonatomic) NSDate *hireDate;
-(double)yearsOfEmployment;
@end
其中 hireDate 属性是指向另一个对象的属性,属性值想对象的时候,需要对内存进行管理。
覆盖方法
覆盖方法的时候只能改变方法的实现,没有必要在.h文件中声明,相应的声明在继承的父类中已经写出。方法的名称、返回类型及实参类型等都必须保持相同。
super
覆盖一个方法的时候。子类可以利用父类方法的结果,而不是整个替换。调用格式为:
[super 实例方法名]
-(float)bodyMassIndex
{float normalBMI = [super bodyMassIndex];return normalBMI * 0.9;
}
继承层次
基本所有的类都继承自 NSObject。

NSObject 拥有很多方法,但是只有一个实例变量:isa 指针。指针类型为创建该对象的类。

给对象发送消息的时候,对象就会通过 isa 指针找到该对象的类查询是否有该消息名的方法,如果没有则查询它的父类。但是如果使用 super 指令,就等于告诉对象,从对象的父类开始查找与之匹配的指定的方法。
由于继承中子类只 import 了父类的头文件,所以看不到父类之中的变量与函数,所以变量通过 self.变量名 操作。
6.类扩展
不是所有的属性或方法都需要在类的头文件中声明,有的属性或方法是类的内部或者类的实例才需要使用的,设计实现细节的属性或方法最好在类扩展中声明。类似于私有成员与函数。
#import "Employee.h"
@interface Employee()
@property (nonatomic) unsigned int officeAlarmCode;
@end@implementation Employee
...
类扩展以 @interface 开始,@end 结束。类名后面加 ()。这样的改动会让变量成为私有成员。
- 在类外不能通过 对象名 . officeAlarmCode 访问这个变量
7.循环引用与内存泄露
Employee 持有一个 Asset* 类型的 holder 指针标识持有关系,每一个 Asset 中也存在一个 Employee* 类型的 holder 指针标识所属关系。

- 当使用 Asset 类和 Employee 类时,为了保持两者间的关系一致,可以在将 所属对象加入主对象的 collection 对象的同时,设置指向主对象的指针。
-(void)addAsset:(Asset*)a
{if(!assets){assets = [NSMutableArray new];}[assets addObject:a];a.holder = self;
}
以上简单处理的“相互拥有”的所属关系导致的相关对象都无法被释放,这种情况就是 强循环引用 导致的内存泄露。
- 类似与 C++ 中的 weakptr,此处需要引入弱引用的思想解决泄露问题。
弱引用
弱引用是不说明所有权的指针,不增加引用计数。
@property (nonatomic, weak) Employee *holder;或
_weak Employee *holder;
当弱引用指向的对象被释放时,相应的指针变量会被复位 nil。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
