oc小练习

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的几种适用场合:任务完成时回调处理,消息监听回调处理,错误回调处理,枚举回调,视图动画、变换,排序
 */


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值