1.Copy和retain的区别
(1)copy:建立一个索引数为1的对象,然后释放旧对象
使用范围:对NSString,在赋值时使用传入值的一份拷贝。拷贝工作由copy方法执行,此属性只对那些实行了NSCopying协议的对象类型有效。
(2)retain:
释放(release)旧对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1
使用范围:
对其他NSObject和其子类。 指定retain会在赋值时唤醒传入值的retain消息。此属性只能用于Objective-C对象类型,而不能用于
CoreFoundation对象。(原因很明显,retain会增加对象的引用计数,而基本数据类型或者Core Foundation对象都没有引用计数)。
举例:
Copy其实是建立了一个相同的对象,而retain不是:
比如一个NSSSting对象,地址为为0X5555,内容为@"WASD"
Copy到另一个NSString之后,地址为0X6666,内容相同,为@"WASD",新创建的对象retainCount为1.旧的对象没有变化
Retain到另一个NSString之后,地址相同(建立一个指针,指针拷贝),内容肯定相同,因为地址指向同一块内存,这个对象的retainCount值+1
也就是说,retain是指针拷贝,copy是内容拷贝。
retain的实际语法为:
- (void)setName:(NSString *)newName {
//首先判断是否与旧的对象一致,如果不一致则进行赋值.
if (name != newName) {
//释放旧的对象,retainCount减1
[name release];
//retain新值,retainCount加1
name = [newName retain];
}
}
2 Self和super的区别?
分析解答:
self 和 super 是oc 提供的 两个保留字。 但有根本区别
(1)代表的对象不同:
在动态方法中,self代表着"对象"
在静态方法中,self代表着"类"
(2)是否是隐藏的参数:
self是类的隐藏的参数变量,指向当前调用方法的对象(类也是对象,类对象),另一个隐藏参数是_cmd,代表当前类方法的selector。
super并不是隐藏的参数,它只是一个"编译器指示符",是预编译指令
(3)调用方法的位置不同
self调用自己方法,
super调用父类方法
(4)self和super底层实现原理不同:
当使用 self 调用方法时,会从当前类的方法列表中开始找,如果没有,就从父类中再找;
而当使用 super 时,则从父类的方法列表中开始找,然后调用父类的这个方法。
self的具体实现:
当使用 self 调用时,会使用 objc_msgSend 函数: id objc_msgSend(id theReceiver, SEL theSelector, ...)。第 一个参数是消息接收者,第二个参数是调用的具体类方法的 selector,后面是 selector
方法的可变参数。以 [self setName:] 为例,编译器会替换成调用 objc_msgSend 的函数调用,其中 theReceiver 是 self,theSelector 是 @selector(setName:),这个 selector 是从当前 self 的 class 的方法列表开始找的 setName,当找到后把对应的 selector 传递过去。
super具体实现:
当使用 super 调用时,会使用 objc_msgSendSuper函数:id objc_msgSendSuper(struct objc_super *super,SEL op, ...)第一个参数是个objc_super的结构体,第二个参数还是类似上面的类方法的select
struct objc_super {
id receiver;
Class superClass;
};
当编译器遇到 [super setName:] 时,开始做这几个事:
1)构 建 objc_super 的结构体,此时这个结构体的第一个成员变量 receiver 就是 子类,和 self 相同。而第二个成员变量 superClass 就是指父类
调用 objc_msgSendSuper 的方法,将这个结构体和 setName 的 sel 传递过去。
2)函数里面在做的事情类似这样:从 objc_super 结构体指向的 superClass 的方法列表开始找 setName 的 selector,找到后再以 objc_super->receiver 去调用这个 selector
3 现有如下定义的字符串: NSString * str=@“iphoneAndroid”,能不能对该字符串进行修改,如果能,请输出删除Android后的新字符串。
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
@autoreleasepool {
//定义不可变的字符串
NSString *str = @"iphoneAndroid";
//输出语句%@占位符
NSLog(@"修改前的字符串str的内容:%@",str);
//新创建一个可变字符串,并将其值设置为str.stringWithString的功能是创建一个新字符串,并将他的值设置为":"后面的值.
NSMutableString *mstr = [NSMutableString stringWithString:str];
//定义一个范围变量,NSMakeRange的第一个参数为起始位置,第二个参数为所取范围的长度
NSRange range =NSMakeRange(6, 7);
//删除字符串中自定义范围内的字母 deleteCharactersInRange这个功能是删除指定range中得字符.
[mstr deleteCharactersInRange:range];
//输出截取后的字符串
NSLog(@"修改后的临时字符串:%@",mstr);
}
return 0;
}
4 编程求字符串“100”和“150”按十进制数值做差后的结果以字符串形式输出。
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
@autoreleasepool {
//定义可变字符串并初始化str1,str2
NSMutableString *str1 = [[NSMutableString alloc]initWithString:@"100"];
NSMutableString *str2 = [[NSMutableString alloc]initWithString:@"150"];
//intValue是将字符串转换成整形
int number1 = [str1 intValue];
int number2 = [str2 intValue];
//将int型转变为字符串类型,stringWithFormat为格式控制并转为字符串类型,%d为占位符
NSString *str = [NSString stringWithFormat:@"%d",number1 - number2];
//输出相减后输出的字符串
NSLog(@"字符串%@和%@按十进制数值做差结果用字符串表示为:%@",str1,str2,str);
}
//程序正常退出
return 0;
}
/*
知识点:
1,字符串拼接
NSString *newString = [NSString stringWithFormat:@"%@%@",tempA,tempB];
2,字符转int
int intString = [newString intValue];
3,int转字符
NSString *stringInt = [NSString stringWithFormat:@"%d",intString];
4,字符转float
float floatString = [newString floatValue];
5,float转字符
NSString *stringFloat = [NSString stringWithFormat:@"%f",intString];
*/
5 编写一个程序,用于接受从终端输入的整数,提取并用英文显示这个数的每一位数。例如输入112 输出 One One Two。
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
@autoreleasepool {
//定义字符串数组,用来存放输入的数据
char buffer[100];
//输入提示
printf("请输入所要转换的数字:\n");
//gets系统函数,获取从键盘返回输入的的字符串
gets(buffer);
//定义数组,并进行初始化,存放英文zero到nine
NSArray *numberArr = @[@"zero",@"one",@"two",@"three",@"four",@"five",@"six",@"seven",@"eight",@"nine"];
//调用类方法,定义一个可变数组
NSMutableString *resultStr = [NSMutableString string];
//当前输入字符串数组下标,从0开始
int curLocation = 0;
//字符串数组以'\0'结尾,由系统添加,即当不到输入字符串数组结尾时继续做循环
while (buffer[curLocation] != '\0') {
//'0'字符的ASCII码为48,逐个渐增,减去48转换为整形,则为相应的整形数字
//例如:输入'5'的ASCII码为53,减去48为5,进行类型转换为int,则为整形数字5
int number = buffer[curLocation] - 48;
//appendString:字符串连接,将整形数字对应的英文表示,从之前定义的数组中取出,连接在字符串reultStr后
[resultStr appendString:numberArr[number]];
//英文代表的数字之间以空格隔开
[resultStr appendString:@" "];
//输入字符串字符下标加1,指向下一个
curLocation++;
}
//输出函数,@后跟NSString类型
NSLog(@"输入的数字 %s 相应的英文显示为: %@",buffer,resultStr);
}
//程序正常退出
return 0;
}
/*
知识点:
gets函数:
1,头文件:stdio.h
2,从stdin流中读取字符串,直至接受到换行符或EOF时停止,并将读取的结果存放在str指针所指向的字符数组中。换行符不作为读取串的内容,读取的换行符被转换为null值,并由此来结束字符串。
3,注意:本函数可以无限读取,不会判断上限,所以程序员应该确保str的空间足够大,以便在执行读操作时不发生溢出
appendString:字符串连接.
字符'0'到'9'之间的ASCII码为48,49...57,
比如'6'的ASCII码为54,减去48为6,对应整形数据6;
'7'的ASCII码为55,减去48为7,对应整形数据7;
*/
6 现在有一个有序的数组,要求用户输入一个整数放到数组中还保证这个数组是有序的。例如原数组为@[@1,@3,@5,@7,@9]; 插入8之后为@[@1,@3,@5,@7,@8,@9]
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
@autoreleasepool {
//定义并初始化可变数组,arrayWithArray参数为NSArry
NSMutableArray *insertArr= [NSMutableArray arrayWithArray:@[@1, @3, @5, @7, @9]];
//打印插入前的数组
NSLog(@"插入数据前数组的排序%@",insertArr);
//声明存放要插入数据的变量
int number;
NSLog(@"输入所要插入的数据:");
//输入函数,%d为占位符,输入整形数字
scanf("%d",&number);
//循环遍历可变数组里的数据,下标从0开始,count方法为计算数组长度
for (int i=0; i<insertArr.count; i++) {
//numberWithInt将整形数据转换为NSNumber类型,
//compare比较两个值的大小,
if ([[NSNumber numberWithInt:number]compare:insertArr[i]]<0) {
//如果插入数据比当前数据小,则插入下标为i处位置
[insertArr insertObject:[NSNumber numberWithInt:number] atIndex:i];
//跳出for循环
break;
}
//如果插入数据比可变数组里的所有的数都大
if (i==insertArr.count) {
//将输入的数据类型转换为NSNumber,插入到数组的最后位置
[insertArr insertObject:[NSNumber numberWithInt:number] atIndex:insertArr.count];
}
}
//打印出插入后的数组
NSLog(@"插入数据后的数组排序:%@",insertArr);
}
//程序正常退出
return 0;
}
/*
知识点:
NSArry:用于对象有序集合(数组)
+ (id)arrayWithObjects:(id)firstObject; //类方法用一个对象初始化
+ (id)arrayWithObjects:(id)firstObjects, ...; //类方法用多个对象初始化,默认最后一个为nil表示多个
- (int)count; // 得到array中的对象个数
- (id)objectAtIndex:(int)index; // 得到索引为i的对象
- (BOOL)containsObject:(id)anObject; // 当anObject出现在array中,则返回yes(实际是通过isEqual:方法来判断)
- (unsigned)indexOfObject:(id)anObject; // 查找array中的anObject,并返回其最小索引值。没找到返回NSNotFound.
(id)lastObject; // 得到array中最后一个对象。如果array中没有任何对象存在,则返回nil
NSMutableArray:用于可变的数组
- (void)addObject:(id)anObject; // 在array最后添加anObject, 添加nil是非法的.
- (void)addObjectsFromArray:(NSArray *)otherArray; //在array最后把otherArray中的对象依次添加进去。
- (void)insertObject:(id)anObject atIndex:(int)index; //在索引index处插入anObject, 若index被占用,会把之后的object向后移。
- (void)removeObjectAtIndex:(int)index; //删除index处的对象,后面的对象依次向前移。
- (void)removeObject:(id)anObject; // 删除所有和anObject相等的对象,同样使用isEqual:作为相等比较方法.
- (void)removeAllObjects;
注:我们不能把nil加到array中。但有时候我们真想给array加一个空的对象,可以使用NSNull来做这件事。如:
[myArray addObject:[NSNull null]];
*/
7. 定义一个学生类,需要有姓名,年龄,考试成绩三个成员属性,创建5个对象,属性可以任意值。(Objective-C)
1) 不使用@property,手动编写他们的访问器方法(getter和setter),注意内存管理(手动管理内存)
2) 增加一个便利构造器(快速构造器)
3) 使用NSLog输出学生对象时,输出信息格式为:My Name Is XXX Age Is XXX Score Is XXX
4) 对5个学生对象按照成绩—》年龄—》姓名优先级排序(成绩相同按照年龄排序,成绩年龄相同按照姓名排序(5个学生的属性值自己随便设定,姓名不考虑中文,按26个大小字母排序))
Student.h
@interface Student : NSObject{
//定义成员变量名字
NSString *_name;
//定义成员变量年龄
int _age;
//定义成员变量分数
int _score;
}
//成员变量name的setter方法,变量名首字母必须大写
-(void) setName:(NSString*) name;
//成员变量name的getter方法,可以省略get
-(NSString*) name;
//成员变量age的setter方法,变量名首字母必须大写
-(void) setage:(int) age;
//成员变量age的getter方法,可以省略get
-(int)age;
//成员变量score的setter方法,变量名首字母必须大写
-(void) setScore:(int) score;
//成员变量score的getter方法,可以省略get
-(int)score;
//声明构造函数
-(id) initWithName:(NSString*)name andAge:(int)age andScore:(int)score;
//声明便利(快速)构造器
+(id) stuWithName:(NSString*)name andAge:(int)age andScore:(int)score;
//声明打印学生信息的实例方法
-(void) printStuInfo;
//声明排序方法
-(NSComparisonResult) compareStu:(Student *)stu;
@end
Student.m
#import "Student.h"
//类的实现
@implementation Student
//名字setter方法的实现
-(void)setName:(NSString *)name
{
//首先判断是否与旧的对象一致,如果不一致则进行赋值.
if (_name!=name) {
//释放旧的对象,引用计数减1
[_name release];
//新设置的名字引用计数加1
_name=[name retain];
}
//将新值赋值给旧值
_name=name;
}
//名字getter方法的实现
-(NSString *)name{
return _name;
}
//年龄setter方法的实现
-(void)setage:(int)age{
_age=age;
}
//名字getter方法的实现
-(int)age{
return _age;
}
//分数setter方法的实现
-(void)setScore:(int)score{
_score=score;
}
//分数getter方法的实现
-(int)score{
return _score;
}
//内存回收,当引用计数为0时,会被系统自动回收
-(void)dealloc{
//引用计数减1
[_name release];
//调用父类的内存释放函数
[super dealloc];
}
//实现构造函数
-(id)initWithName:(NSString*)name andAge:(int)age andScore:(int)score
{
NSLog(@"调用构造函数");
//调用父类方法进行初始化
self=[super init];
//如果初始化成功
if (self) {
//将参数值赋值给成员变量
_name=name;//[self setName:name];
_age=age;//[self setName:age];
_score=score;//[self setName:score];
}
//返回类本身
return self;
}
//类方法,便利构造器,参数为:名字,年龄,分数
+(id)stuWithName:(NSString*)name andAge:(int)age andScore:(int)score
{
//输入提示
NSLog(@"调用便利构造器,进行初始化");
//调用构造方法
self=[[self alloc]initWithName:name andAge:age andScore:score];
//将self加入自动释放池,进行管理
[self autorelease];
//返回自身,即student类本身
return self;
}
//实例方法,打印学生信息
-(void)printStuInfo{
//输出函数,格式为My Name Is xxx Age Is xxx Score Is xxx
NSLog(@"My Name Is %@ Age Is %d Score Is %d",self.name,self.age,self.score);
}
//排序函数,作为回调函数被调用
- (NSComparisonResult)compareStu:(Student *)stu
{
//首先按分数排序:先将分数由int型转换为NSNmuber,然后进行比较分数大小,返回NSComparisonResult类型
NSComparisonResult result = [[NSNumber numberWithInt:stu.score]compare:[NSNumber numberWithInt:self.score]];
//如果分数相同,
if (result == NSOrderedSame) {
//按年龄进行排序:先将年龄由int型转换为NSNmuber,然后进行比较年龄大小,返回NSComparisonResult类型
result = [[NSNumber numberWithInt:stu.age]compare:[NSNumber numberWithInt:self.age]];
//如果年龄相同
if(result == NSOrderedSame)
{
//如果年龄相同,则按姓名排序
result = [self.name compare:stu.name];
}
}
//返回拍下后的最后结果
return result;
}
@end
main,m
#import <Foundation/Foundation.h>
#include "Student.h"
#define STUNUMBER 5
int main(int argc, const char * argv[])
{
@autoreleasepool {
//调用类方法创建Student类型的实例s1,s2,s3,s4,s5;
//这个初始化的临时对象不用手动释放,类方法的便利构造器初始化实例变量后不用手动release,然后直接用stu来调用类的方法来使用被初始化的值
Student *stu1 = [Student stuWithName:@"firstName" andAge:23 andScore:60];
Student *stu2 = [Student stuWithName:@"secondtName" andAge:21 andScore:80];
Student *stu3 = [Student stuWithName:@"thirdName" andAge:25 andScore:90];
Student *stu4 = [Student stuWithName:@"fourthName" andAge:23 andScore:80];
Student *stu5 = [Student stuWithName:@"fifthName" andAge:24 andScore:70];
//打印排序前每个实例对象的名字,年龄和分数信息
[stu1 printStuInfo];
[stu2 printStuInfo];
[stu3 printStuInfo];
[stu4 printStuInfo];
[stu5 printStuInfo];
//定义一个数组,用创建的实例进行初始化
//arrayWithObjects最后一个参数为nil,参数为表示多个对象
NSArray *array = [NSArray arrayWithObjects:stu1,stu2,stu3,stu4,stu5,nil];
//调用回调函数comparestu,对数组进行排序,@selector为选择器
NSArray *sortarray=[array sortedArrayUsingSelector:@selector(compareStu:)];
//排序后学生的信息
NSLog(@"----------------排序后学生的信息---------------:");
//遍历数组
[sortarray enumerateObjectsUsingBlock:^(Student *stu, NSUInteger integer, BOOL *stop) {
//NSUInteger转变为int型
int num = (int )integer;
//输出排序后学生的信息
NSLog(@"(%d)MyName Is %@ Age Is %d Score Is %d",num+1,stu.name,stu.age,stu.score);
}];
}
return 0;
}
/*
知识点:
- (NSArray *)sortedArrayUsingSelector : (SEL)aSelector
返回一个数组,该数组是旧数组的元素经过选择器排序后的新数组。
(SEL)可以是@selector类型,为所调用的回调函数
- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block;
在遍历数组NSArry中,我们可以加工stop设为YES则跳出循环,void(^)为block代码块
(1)用block作为回调函数,可以使得程序员在写代码更顺畅,不用中途跑到另一个地方写一个回调函数,有时还要考虑这个回调函数放在哪里比较合适。采用block,可以在调用函数时直接写后续处理代码,将其作为参数传递过去,供其任务执行结束时回调。
(2)另一个好处,就是采用block作为回调,可以直接访问局部变量。比如我要在一批用户中修改一个用户的name,修改完成后通过回调更新对应用户的单元格UI。这时候我需要知道对应用户单元格的index,如果采用传统回调方式,要嘛需要将index带过去,回调时再回传过来;要嘛通过外部作用域记录当前操作单元格的index(这限制了一次只能修改一个用户的name);要嘛遍历找到对应用户。而使用block,则可以直接访问单元格的index。
(3)适用环境:份文档中提到block的几种适用场合:任务完成时回调处理,消息监听回调处理,错误回调处理,枚举回调,视图动画、变换,排序
*/