iOS的一些基础知识

来源:互联网 发布:芬兰 桑拿日 知乎 编辑:程序博客网 时间:2024/04/28 08:43

转自:http://www.devdiv.com/home.php?mod=space&uid=10681&do=blog&id=9654

iOS的一些基础知识

2012.7.17

第一章 基础知识


Object-C语言不允许多继承,也就是同时继承多个父类。因此,每一个类只有一个最直接的抽象父类。


Master-Detail Application:这个工程模板将会给你创建一个split View Controller左右切换分割的应用程序,splitView Controller将会在我们第二个章节的内容中提到.

Page-Based Application:这个模板将会帮你创建一个类似翻页的基础应用程序,你将会通过我们的第二章节学到更多关于这个模板的一些知识。

Empty Application:这个模板是一个空的工程程序,只是创建了一些简单的工程文件。没有一些基础的设置,一些基础的设置你都可以按照你的要求去添加。


声明一个变量:如果这个变量名字是一个单词,那么所有的单词都必须小写,如果这个变量名称是有多个单词组成,那么第一个单词必须全部小写,后面单词的每一个开头字母需要大写,其他的小写。比如"firstcounter"可以声明它为"firstCounter" ,变量名一般最好不要有下划线,变量名称最好只包含英文字母和数字,不要什么特殊符号。


NSInteger能用来保存有符号的(正或者负)的整形变量.
NSUInteger 用来表示无符号的,要么是正,要么是负的整形变量。
Float 浮点型的数据,例如1.23
NString string 类型的数据,比如"MrsThomson"
NSArray
其实也就是一个数组,比如说你有十个文件对象,那么你可以把他们保存在这个里面.NSSet你可以保存唯一的,没有重复的集合对象。

我们使用双等于号,其实就是表示一个判断的过程,判断两个值是否相等。这样编译器在编译之后能得到一个YES或者NO的判断结果值。

NSInteger integer1 = 123; NSInteger integer2 = 456;

if (integer1 == integer2){ NSLog(@"Integers are equal.");

} else {
NSLog(@"Integers are not equal.");

}

如果你比较的是一些对象,那么你最好使用isEqual:方法来进行判断。实例代码如下:

NSObject *object1 = [[NSObject alloc] init]; NSObject *object2 = object1;
if ([object1 isEqual:object2]){

NSLog(@"Both objects are equal."); } else {

NSLog(@"Objects are not equal."); }


可以按以下几步在.m文件中创建目标类:

  1. 类型(如果你想要一个实例方法或一个类的方法。
  2. 选择你的方法的返回类型,并括在括号内,例如:(void)没有返回值,(Bool)一个布尔值,
    (NSObject*)返回 NSObject 的一个实例,等等。 
  3. 选择一个方法的名称,以小写字母开头。在Objective-C,方法名常以小写字母开头,例如:
    sendEmailTo 代替SendEmailTo 
  4. 如果你不想你的方法含有何参数,直接跳到步骤9 
  5. 给参数取两个名称。一个名称作为方法名称的一部分,将会被外部的方法所用到(除了第一个参数
    ,其他所有参数都是可选的)。另一个名称将被作为方法内的一个参数名。但有一个例外,就是方法的第一个参数名是在第三步选择的方法的一部分。对于这第一个参数,你只能选择第二个名称作为方法内部的方法名。 
  6. 给参数取好名字后,给方法选择数据类型并括在括号内。 
  7. 在你的参数的第一个所选名称后加上冒号(如果有),并加上括号,括号里依次为方法的数据类型和
    参数的第二个名称。 
  8. 为其他参数重复第 5 7步骤。 
  9. 在方法名和参数后插入一个开放的大括号({)(假如有参数的话),并以一个右大括号(})结束。
    回到我们前面看到的 sendEmailTo 程序的例子,试着在 Objective-C里创建一个相同的方法

- (BOOL) sendEmailTo:(NSString *)paramTo withSubject:(NSString *)paramSubject andEmailMessage:(NSString *)paramEmailMessage{ /* Send the email and return an appropriate value */ if ([paramTo length] == 0 ||

[paramSubject length] == 0 || [paramEmailMessage length] == 0){
/* One or some of the parameters are empty */ NSLog(@"Empty parameter(s) is/are provided."); return NO;
}
return YES;

}

这是一个返回一个布尔值(Bool)实例方法,这个方法名为 sendEmailTo:WithSubject: andEmailMesssage:。并且它有三个参数。然后我们可以用下面的代码来调用这个方法:

[self sendEmailTo:@"someone@somewhere.com" withSubject:@"My Subject" andEmailMessage:@"Please read my email."];

如前所述,每一个参数的第一个名字(除了第一个)是可选的。换句话说,我们可以使用不同的名称来构 sendEmailTo:WithSubject:andEmailMessage:方法:

- (BOOL) sendEmailTo:(NSString *)paramTo :(NSString *)paramSubject
:(NSString *)paramEmailMessage{
/* Send the email and return an appropriate value */ if (paramTo length] == 0 ||

[paramSubject length] == 0 || [paramEmailMessage length] == 0){ NSLog(@"Empty parameter(s) is/are provided."); return NO;
}
return YES;
}

强烈不建议写没有额外名称参数的方法。这是一个很糟糕的编程习惯,它会使你混淆,并且和你一起工作的团队会忽视你记录好的代码。我们可以这样调用这个方法:

[self sendEmailTo:@"someone@somewhere.com" :@"My Subject"
:@"Please read my email."];




分配初始化对象


必须先分配和初始化一个对象才能使用它。可以使用 alloc这个实例方法来分配一个对象。该类方法会为对象、对象的实例和方法分配内存空间。但是,被分配的内存并未定义。所以,每个对象必须初始化,就是给它赋上初值。

一个初始化方法必须是特定的初始化,通常是具有很多参数的初始化方法。例如:initWithFrame:这个方法是 UIView 类的对象的一个特定初始化方法。所以,在使用对象之前先分配和初始化它。

当执行一个新的对象时,不要重载 alloc这个方法。这个方法是在声明在 NSObject里的。相反的,而是为特定对象处理所需参数重载 init方法和创建自定义方法。

MyObject *someObject = [[MyObject alloc] init];



添加类的属性


需要利用XXX.AA的方式来直接访问类中的变量,而不是采用调用方法的方式来访问.

使用关键字@property给类定义属性。


任何一个通过点表示的都是一个属性。属性是方法的快捷方式。什么意思呢?先看一个范例:

NSObject *myObject = [[NSObject alloc] init]; 

myObject.accessibilityHint = @"Some string";

到底属性是什么呢?当定义一个属性时,会告诉编译器我们将会给这个属性写上一个settergetter方法。如果在这个属性里设置一个值,运行时将执行setter方法。如果读取属性,则执行的getter方法。我们不必手动编写这两个方法的属性。我们可以在.m文件中使用@synthesize关键字让编译器自动为属性生成settergtter方法:

@property(nonatomic, copy) NSString *accessibilityHint;


假如要定义一个只读属性,你所需要做的就是用@readonly关键字定义它,例如:

@property (nonatomic, strong, readonly) NSString *lastName;

注意:
对于一个只读属性,改变它的值只有一个办法,即在该类中定义属性成员的变量。


使用协议委托任务(不太明白  等求证)

协议是一个声明某些方法及属性并储存在实体文档。(通常延伸档名是.h)任何实践协议的对象,都必须实践协议提供的方法及属性(可在协议中指定是必须或可选)



NSString类是不能更改的,NSString类一旦被创建,内容就不能被修改了。可变字符串NSMutableString创建以后还可以被修改。我们接下来很快会看到两种类的例子。

Objective-C字符串应该用双引号括起来。双引号的前面应该加上@符号。例如,”Hello,world”这个字符串Objective-C中应该表示为:

@” Hello, world”
有很多种方法可以把一个字符串赋给NSStringNSMutableString类的实例。如下:

NSString *simpleString = @"This is a simple string";

NSString *anotherString = [NSStringstringWithString:@"This is another simple string"];

 NSString *oneMorestring =[[NSStringalloc] initWithString:@"One more!"];

NSMutableString *mutableOne = [NSMutableStringstringWithString:@"Mutable String"]; 

NSMutableString *anotherMutableOne = [[NSMutableStringalloc] initWithString:@"A retained one"]; NSMutableString *thirdMutableOne = [NSMutableStringstringWithString:simpleString];

运行时你可能不时的需要得到字符串的长度来做出某些操作。通过调用NSString类或者其他子类例如NSMutableString的实例的length方法你可以实现这个功能。

if ([userName length] == 0)


另一个你可能想知道的关于字符串的功能是如何把一个字符串转换成整型。例如,字符串转int ,float double类型。你可以使用NSString(或者它的子类) integerValue, floatValue,doubleValue 方法来获得int ,floatdouble类型的值。

例如:NSString *simpleString = @"123.456"; 

NSIntegerintegerOfString = [simpleString integerValue]; 

NSLog(@"integerOfString = %ld", (long)integerOfString); 

CGFloatfloatOfString = [simpleString floatValue]; NSLog(@"floatOfString = %f", floatOfString); doubledoubleOfString = [simpleString doubleValue]; NSLog(@"doubleOfString = %f", doubleOfString);

integerOfString = 123 floatOfString = 123.456001 doubleOfString = 123.456000

如果你喜欢使用C语言库里的字符串,就不需要使用@符号了。比如:char *cString = "This is a C String";

如果你想把一个NSString转换成C库里的字符串,必须用NSStringUTF8String。例如:

const char *cString = [@"Objective-C String" UTF8String]; 

NSLog(@"cString = %s", cString);

你可以使用%S将一个C字符串格式化输出到控制台。相应的,使用%@来格式输出NSString对象。

要把一个C字符串转换成NSString,必须使用 NSString类的 stringWithUTF8String:方法,如下:

NSString *objectString = [NSString stringWithUTF8String:"C String"]; NSLog(@"objectString = %@", objectString);
In order to find a string inside another string, you can use the rangeOfString: method ofNSString. The return value of this method is of type NSRange:

typedefstruct _NSRange { NSUInteger location; NSUInteger length;

} NSRange;


如果你要查找的字符串()在一个目标字符串(草垛),NSRange结构的location成员将被置为从零开始的索引用来表示第一个针在草垛中的位置。如果草垛中不包含针,location值会给设为NSNotFound。我们来看这个例子:

NSString *haystack = @"My Simple String"; NSString *needle = @"Simple";
NSRange range = [haystack rangeOfString:needle]; if (range.location == NSNotFound){

/* Could NOT find needle in haystack */
} else {
/* Found the needle in the haystack */ NSLog(@"Found %@ in %@ at location %lu", needle,

haystack,
(unsigned long)range.location); }

Tips:用来查询的 NSString类的rangeOfString 方法是大小写敏感的。



在对象中使用整型或封装好的数字。

NSNumber类来用面向对象的方法处理数字。如果你只需要简单的数字(而不是对象),NSInteger

类来操作有符号数(正数或者负数),NSUInteger类来操作无符号数(正数或0), CGFloat类和double在操作浮点数。

正如我们用NSString对象来存储字符串,我们可以用NSNumber对象来存储数字。你可能会问为什么?

答案很简单:允许一个对象存储数字的值可以让我们方便的把数字存到磁盘,从磁盘取出。还能用一个简单的对象存储有符号、无符号以及浮点数,不要定义和转换各种不同类型的变量。变量的类型是无穷尽的。

让我们来看看NSNumber对象的构造函数:

NSNumber *signedNumber = [NSNumbernumberWithInteger:-123456];
NSNumber *unsignedNumber = [NSNumber numberWithUnsignedInteger:123456]; NSNumber *floatNumber = [NSNumber numberWithFloat:123456.123456f]; NSNumber *doubleNumber = [NSNumber numberWithDouble:123456.1234567890];


NSArrayNSMutableArray类把多个对象存储到操作相对更加方便的数组中。

你可以把任何NSObject类或者它子类的对象放到NSArray类型中。

NSArrayNSMutableArray 的主要区别是NSMutableArray可以在分配空间和初始化之后修改,然而NSArray不可以被修改。

让我没来看一个例子。让我们创建一个NSString实例,两个NSNumber实例并且把它们存到一个不可变数组中:

NSString *stringObject = @"My String";
NSNumber *signedNumber = [NSNumbernumberWithInteger:-123]; NSNumber *unsignedNumber = [NSNumber numberWithUnsignedInteger:123]; NSArray *array = [[NSArrayalloc] initWithObjects:
stringObject,
signedNumber,
unsignedNumber, nil];
NSLog(@"array = %@", array);

你可以看到,我们用initWithObjects:来初始化 array。当你用这个初始化函数时,把你要存储的对象一个一个传递进去。最后用一个nil符号结束这个列表以通知运行时列表什么时候结束。如果你不这么做,LLVM编译器会抛出一个如下的异常:
warning: Semantic Issue: Missing sentinel in method dispatch

我们也可以用NSArray类的arrayWithObjects:方法来创建一个可自动释放的数组。像这样:NSArray *array = [NSArray arrayWithObjects: stringObject,signedNumber,unsignedNumber, nil];


你可以调用数组的count方法类得到数组中的对象个数。
你也可以通过 for循环或者枚举来遍历数组。让我们首先来看一下用for循环解决的第一种方案。

NSArray *array = [NSArrayarrayWithObjects: stringObject,
signedNumber,
unsignedNumber,nil];

NSUInteger counter = 0; 

for (counter = 0

counter< [array count];
counter++){
id object = [array objectAtIndex:counter]; NSLog(@"Object = %@", object);
}

就像你看到的,我们用objectAtIndex:方法来获得一个指定位置的对象。
记住索引时从 0开始的。换句话说,当计数器到达-1时循环必须停止因为在数组中没有负索引。

可变数组非常有趣,就像你猜想的一样,不可变字符串一旦被分配了内存且初始化之后就不能修改了。但是数组在分配空间初始化之后可以被修改。让我们来看个例子:

NSString *stringObject = @"My String";
NSNumber *signedNumber = [NSNumbernumberWithInteger:-123]; NSNumber *unsignedNumber = [NSNumber numberWithUnsignedInteger:123]; NSArray *anotherArray = [[NSArrayalloc] initWithObjects:
@"String 1",
@"String 2",
@"String 3", nil];
NSMutableArray *array = [[NSMutableArrayalloc] initWithObjects: stringObject,
signedNumber, nil];
[arrayaddObject:unsignedNumber];

[arrayremoveObject:signedNumber]; [arrayaddObjectsFromArray:anotherArray]; for (id object in array){
NSLog(@"Object = %@", object);
}

分析这段代码之前,让我们来看下输出:

Object = My String Object = 123 Object = String 1 Object = String 2 Object = String 3

你可能会问发生了什么,那么让我们来看看我们都用了NSMutableArray类的哪些方法:
addObject:
这个方法允许我们在个可变数组的末尾添加一个对象。
removeObject: 使用这个方法,我们可以删除数组中的一个指定对象。记住删除对象时,我们传递的参数是对象,而不是对象的索引。

想要通过索引来删除数组中的对象,必须使用removeObjectAtIndex方法。

addObjectsFromArray:
通过这个方法,我们可以将一个可变或不可变数组添加到一个可变数组中。

请记住,在使用快速枚举或不可变数组的过程中,禁止向数组添加对象或许从数组删除对象,否则

就会引起运行时错误。这是可变数组快速排序时的默认行为。系统会自动实现。

数组排序

NSOrderedSame

参与比较的两个值相等。

NSOrderedAscending

左边的值比右边的小。这么来记:从左到右是升序的,意味着左边的值更小一些。

NSOrderedDescending

右边的值比左边的小。换句话说:从左到右是降序的,意味着左边的值更大一些。


使用NSDictionary类以及可改变长度的NSMutableDictionary类。

一个dictionary是一个特殊数组,其中的每个项都包含一个key.这事dictionaryarray唯一不同的地方。

array的每一项(对象)都有一个数字的索引,然而dictionary中的每一项(对象)都有一个key。解释一下,假设我们要把一个人的姓、名字以及年龄存储到一个array和一个dictionary中。我们应该按以下方式存储:

NSArray *person = [[NSArrayalloc] initWithObjects: @"Anthony",

@"Robbins",
[NSNumber numberWithUnsignedInteger:51], nil]; NSLog(@"First Name = %@", [person objectAtIndex:0]); NSLog(@"Last Name = %@", [person objectAtIndex:1]); NSLog(@"Age = %@", [person objectAtIndex:2]);

可以看到我们用索引来获取array中的对象。使用dictionaries,每个对象都有一个key值。这个key是个对象,我们可以用它来访问dictionaries中的值。

我们来看相同的例子用dictionaries怎么做。我们有一个key"First Name"对应"Anthony",以此类推:

NSNumber *age = [NSNumber numberWithUnsignedInteger:51]; NSDictionary *person = [[NSDictionaryalloc] initWithObjectsAndKeys: @"Anthony", @"First Name",

@"Robbins", @"Last Name", age, @"Age",
nil];

NSLog(@"First Name = %@", [person objectForKey:@"First Name"]); NSLog(@"Last Name = %@", [person objectForKey:@"Last Name"]); NSLog(@"Age = %@", [person objectForKey:@"Age"]);
The results will then be printed out as shown here:

First Name = Anthony Last Name = Robbins Age = 51

可以看到,我们用值和键的对儿初始化dictionary。我们在先传递值,然后传值对应的 key。当我们用 NSLog输出时,key作参数调用objectForKey:方法来输出 key对应的value值。NSDictionary对应的可改变dictionaryNSMutableDictionary在分配内存和初始化之后可以被修改。例如,如果在dictionary初始化之后想从其中删除Age这个key对应的对象,我们应该这么做:

NSNumber *age = [NSNumber numberWithUnsignedInteger:51]; NSMutableDictionary *person = [[NSMutableDictionaryalloc] initWithObjectsAndKeys:
@"Anthony", @"First Name",

@"Robbins", @"Last Name", age, @"Age",

nil];
[personremoveObjectForKey:@"Age"];
NSLog(@"First Name = %@", [person objectForKey:@"First Name"]); NSLog(@"Last Name = %@", [person objectForKey:@"Last Name"]); NSLog(@"Age = %@", [person objectForKey:@"Age"]);

我们方便的删除了与Age这个key对应的对象。注意到"Age"不只为空了,而且以及不存在了。


如果想枚举dictionary中所有的key,可以简单用 enumerateKeysAndObjectsUsingBlock:方法。在前文体到array ,enumerateKeysAndObjectsUsingBlock方法会输出"FirstName""Last Name",但没有"Age",为已经被删除了。这个方法的参数是一个包含3个参数而且没有返回值的块对象。3个参数如下:

Key
标识当前正在枚举的 key的一个id
Object
也是一个 id,标识当前key对应的对象。
一个 BOOL型指针
在枚举的过程中,你可以随时通过给这个指针传一个YES值来停止这个进程。如果想遍历dictionary中所有key就别动这个指针。

如果你不想用块对象来快速枚举,可以采用dictionaryallKeys方法来做。一旦得到所有的key就可以通objectFor

Key:方法并用这些 key来找到对应的对象。像这样:

for (id keyInDictionary in [person allKeys]){
idobjectForKey = [person objectForKey:keyInDictionary];
NSLog(@"Key = %@, Object For Key = %@", keyInDictionary, objectForKey); }



用集合(sets)来代替数组。.


Setsarray非常相似。二者最大的区别就是sets中相同对象只能被添加一次。当你第二次添加同一个对

象时,sets会拒绝添加。
我们使用 NSSet类表示不可改变的sets, NSMutableSet类表示可变sets.我们来看一个不可变 sets的例子:

NSString *hisName = @"Robert";
NSString *hisLastName = @"Kiyosaki";
NSString *herName = @"Kim";
NSString *herLastName = @"Kiyosaki";
NSSet *setOfNames = [[NSSetalloc] initWithObjects: hisName,
hisLastName,
herName,
herLastName, nil];
NSLog(@"Set = %@", setOfNames);

你可以看到名字Kiyosaki只添加了一次。Set拒绝将同一个对象加入列表两次。一个set不仅仅比较对象在内存中的位置,而且比较这些对象的内容,了解这点非常重要。hisLastNameherLastName是两个不同的变量,它们在内存中的地址不同。然而set知道我们传递了两个NSString的实例给它,而且可以比较这些字符串从而发现我们已经添加过了一个Kiyosaki名字。所以set中只留下了一个实例。

现在我们来看一下如何构造一个可变sets:

NSMutableSet *setOfNames = [[NSMutableSetalloc] initWithObjects: hisName,
hisLastName, nil];
[setOfNamesaddObject:herName]; [setOfNamesaddObject:herLastName];

我们可以方便的通过NSMutableSet类的addObject:方法类像 set添加一个新的对象。你也可以用removeObject方法来删除对象。同样要记住对象的内容,不只是地址。所以如果想从一个set中删除一个字符,可以将字符串传递给removeObject:方法,即使新字符串是内存中的不同变量。只要这个字符串/对象的内容相同你就可以得到想要的结果。

如果你想快速遍历一个set中所有的对象,可以使用enumerateObjectsUsing Block:方法。传递给这个方法的块对象没有返回值,有两个参数:
一个 id类型的key
包含 set中当前枚举的对象。

一个BOOL类型的指针
你可以随时将一个 booleanYES传给这个指针来停止遍历。我们来看个例子。假设我们想在一个set中查找字符串Kiyosaki:

[setOfNamesenumerateObjectsUsingBlock:^(__strong id obj, BOOL *stop) { if ([objisKindOfClass:[NSString class]]){
NSString *string = (NSString *)obj;
if ([string isEqualToString:@"Kiyosaki"]){

NSLog(@"Found %@ in the set", string); *stop = YES;
}
}

}];

如果能在在set中找到一个Kiyosaki,我们将字符串打印到控制台。然后通过将YES值传给遍历块对象的第二个参数来结束遍历。还有其他手动方法。用count方法来获得set中的对象个数。也可以用allObjects法来获得set中包含所有对象的数组。

如果想在set中获取一个对象,调用setanyObject方法。就像函数名代表的,这个函数返回set中一个随机的对象。如果set为空,则返回空。

注意不可变的空set绝对是没有用的。它是空的而且在它的生命周期中一直为空。


程序包的一些知识(有待学习)


通过App发布一条通知同时允许其他对象接收通知并采取行动,这取决于你发布的通知。


使用 NSNotificationCenter default notificationcenterpostNotificationName:object:userInfo:的实例方法发

布一条通知,其中携带一个对象(通常此对象激活通知)和一条用户信息词典,词典中包含了关于词条通知和/或者激活通知的对象的额外信息。