iOS开发中static变量的三大作用
- 所有未加static前缀的全局变量和函数都具有全局可见性
- 可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。Static可以用作函数和变量的前缀,对于函数来讲,static的作用仅限于隐藏,而对于变量,static还有下面两个作用。
- static的第二个作用是保持变量内容的持久
存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化
#include <stdio.h>
int fun(void){
static int count = 10;
return count--;
}
int count = 1;
int main(void)
{
printf("global\t\tlocal static\n");
for(; count <= 10; ++count)
printf("%d\t\t%d\n", count, fun());
return 0;
}
运行结果
global local static
1 10
2 9
3 8
4 7
5 6
6 5
7 4
8 3
9 2
10 1
就可以看出函数里面的赋值只有程序开始运行的时候用了一下,剩下时间不管怎样轮到他,他都不会执行,因为只进行一次
- static的第三个作用是默认初始化为0
其实全局变量也具备这一属性,因为全局变量也存储在静态数据区。在静态数据区, 内存中所有的字节默认值都是0x00,某些时候这一特点可以减少程序员的工作量。比如初始化一个稀疏矩阵, 我们可以一个一个地把所有元素都置0,然后把不是0的几个元素赋值。如果定义成静态的,就省去了一开始置0的操作。 再比如要把一个字符数组当字符串来用,但又觉得每次在字符数组末尾加’\0’太麻烦。如果把字符串定义成静态的, 就省去了这个麻烦,因为那里本来就是’\0’。 首先static的最主要功能是隐藏,其次因为static变量存放在静态存储区,所以它具备持久性和默认值0。
类别(category)与扩展
OC中并没有提供抽象类的语法支持:定义一个父类,并以其派生多个子类,其他程序使用这些类的时,总是面向父类编程,当程序调用父类的初始化方法,静态方法来返回对象时,实际上返回 的是子类的实例。这系列的类被称为一个类簇,此时这个父类模拟了抽象类的功能。
类别:@interface 已有类 (类别名)
……
@end
一般习惯将类别的接口文件命名为“类名+类别名.h/m”的形式,实现了对原有类的动态扩展。 虽然类别可以重写原有类中的方法,通常不推荐这么做,更好的建议是通过原有类派生子类,然后在子类中重写父类原有的方法
- 通过类别为指定类添加了新方法后,此新方法不仅会影响原有类,同时会影响原有类中的所有子类,每个子类都会获取类别中的扩展方法。
- 可以为一个类定义多个类别,不同的类别都可以对原有类增加方法定义。
- 利用类别对类进行模块化设计(之前无法将类的实现部分分布到多个.m文件中)
例如@interface NSWindow(NSKeyboardUI)之类的类别 针对该接口可以提供其专门的实现文件,可以对类实现按模块分布到不同的.m文件中,从而提高项目后期的可维护性 - 使用类别来调用私有方法(没有在接口部分定义而是在实现部分定义的方法相当于私有方法,通常不允许被调用)
- OC中实际上并没有真正私有的方法,如果使用NSObject的performSelector:方法来执行动态调用,完全可以调用那些私有方法,但如果使用此方法来执行调用,则会完全避开编译器的
语法检查。(未必是一种好做法) - 可以通过类别定义向前引用,实现对私有方法的调用
@interface FKItem (FK)
-(double) calDiscount:(double) discount;
@end
告诉编译器FKItem类中可以包含calDiscount:方法,防止编译器报错。 //在类别中声明之前才实现部分新增的方法 3. 使用类别来实现非正式协议 这种类别以NSObject为基础,为NSObject创建类别,创建类别时计科指定该类别应该新增的方法。
扩展(extension)
扩展相当于匿名类别
@interface 已有类() {
实例变量
}
……
@end
可以发现扩展可以额外增加实例变量,可以使用@property来合成setter,getter方法 (但定义类的列表时,则不允许额外定义实例变量) 在实现部分仅导入接口部分的.h不够,还需导入扩展部分的.h文件。 测试原有类时同样需要#import该类的扩展文件,仅导入类接口应以的文件不够。
协议(protocol)
协议不提供任何实现,协议体现的是规范和实现分离的设计哲学 让规范和实现分离正是协议的好处,一种松耦合的设计 协议里通常是定义一组公用方法,但不会为这些方法提供实现,方法实现的规则交给类去完成。
正式协议的定义
使用@protocol关键字
@protocol 协议名 <父协议1, 父协议2> {
多个方法定义
}
- 一个协议可以有多个直接父协议,且协议只能继承协议
- 协议中定义的犯法只有方法签名,没有方法实现;且其中包含的方法既可以时类方法也可以是实例方法,且协议里所有的方法都是公开的访问权限。
实现协议
@interface 类名: 父类 <协议1, 协议2…>
(OC编译器也使用implement作为实现协议的说法) 可以使用协议来定义变量,那么这些变量只能调用该协议中声明的方法,否则编译器会提示错误。
NSObject<协议1,协议2,…>* 变量
id<协议1,协议2,…> 变量
编译时类型仅是所遵守的协议类型,因此只能调用该协议中的方法。 (使用协议来定义变量,就像在其他语言中使用接口定义变量的语法。)
正式协议与非正式协议的区别
非正式协议通过继承特定类别的NSObject来实现,遵守正式协议有专门的Objective—C语法 弥补正式协议的关键字 @optional:位于该关键字之后,required或end之前声明的方法是可选的。 @required:位于该关键字之后,optional或end之前声明的方法是必需的。
@protocol FKA
@optional
(void) output;
@required
(void) addData:(NSSTring*) msg;
@end
通过这两个关键字,正式协议完全可以替代非正式协议的功能
Foundation框架
字符串NSString & NSMutableString
第一个字符序列不可变的字符串 第二个字符序列可变的字符串 NSString的常用功能 NSString类是不可变类,一旦被创建,包含在这个对象中的字符序列是不可改变的,直到这个对象被销毁。
str = [str stringByAppendingString @"iOS!"]
const char* cstr = [str UTF8String]
str = [str stringByAppendingFormat:@"%@iOS", book];
[str length];
[str lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
[str substringToIndex:10];
[str substringFromIndex:5];
[str substringWithRange:NSMakeRange(5, 15)];
NSRange pos = [str rangeOfString:@"iOS"];
[str uppercaseString];
NSRange只是一个结构体有两个分别代表起始位置和长度的unsigned int的整型值 可变字符串NSMutableString 其是NSString的子类,NSString的方法其都可以直接使用,其对想也可以直接当成NSString对象使用
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSString* book = @"IOSbook";
NSMutableString* str = [NSMutableString stringWithString:@"hello"];
[str appendString:@"IOS!!!"];
NSLog(@"%@", str);
[str appendFormat:@"%@ is a nice book", book];
NSLog(@"%@", str);
[str insertString:@"fkit.org" atIndex:6];
NSLog(@"%@", str);
[str deleteCharactersInRange:NSMakeRange(6, 12)];
NSLog(@"%@", str);
[str replaceCharactersInRange:NSMakeRange(6, 9) withString:@"objective-C"];
NSLog(@"%@", str);
}
return 0;
}
|