iOS_oc小知识点

自己学习中总结的 比较零散,见谅

1 。错误问题

1. // error:instance variable 'age' accessed in class method
// 实例变量age不能在类方法中访问

2. //-[Person test]: unrecognized selector sent to instance 0x7fd2ea4097c0
//给Person对象发送了一个不能识别的消息:test
3.//-[Person printClassName]: unrecognized selector sent to instance 0x7fa520c0b370
// 系统会认为现在调用的printClassName是个对象方法
//[p printClassName];
4.//EXC_BAD_ACCESS : 访问了一块坏的内存(已经被回收、已经不可用的内存
5.//-[Person setAge:]: message sent to deallocated instance 0x100109a10 给已经释放的对象发送了一条-setAge:消息:


@:OC语言中可以代表对象的格式占位符号

self:指向了方向调用者,代表着当前对象


//判断stu是不是Student这个类的实例
BOOL b =[stu isKindOfClass:[Student class]];


//枚举遍历,快速遍历出value值
 NSDictionary *dictionary = [[NSDictionary alloc]initWithObjectsAndKeys: @25,@"number",
                             @23.4,@"numberfloat",
                             @YES,@"bool",
                             @"a",@"ocstring",
                             @'a',@"oString",
                             nil];
    NSEnumerator *enu = [dictionary objectEnumerator];
    id obj;
    while (obj = [enu nextObject]) {
        NSLog(@"%@",obj);
    }

//字符串常量,存在只读数据区
char *c = "helloworld";
//字符数组,字符串常量需要在运行时拷贝到数组中
char ch[] = "helloworld";


voaltile说明符和const 正好相反,明确告诉编译器,指定类型变量的值会改变。(I/O端口) 比如要将输出端口的地址存储在 outPort 的变量中。

volatile char *outPort;

*outPort = 'O';

*outPort = 'N';

这样就可以避免编译器将第一个赋值语句从程序中删除


创建的类对象包含了指向超类的指针、 类名和指向类方法的列表的指针。 类对象还包含一个long 的数据, 为新创建的类对象指定大小。

//逐个字符比较 不区分大小写的比较.  注意:NSComparisonResult 是一个枚举值
-(NSComparisonResult)compare :(NSString *)string;
-(NSComparisonResult)compare :(NSString *)string options:(unsigned)mask;


//将字符串切分成数据
使用 componentsSeparatedByString : 来切分 NSArray,
NSString *string = @"oop : ack : bork : greeble : ponies" ;
NSArray *chunks = [string componentsSeparatedByString : @":"];
//将数组合并成字符串
使用 componentsJoinedByString : 来合并 NSArray 中的元素并创建字符串 string = [chunks componentsJoinedByString :@":-)"] ;

//typedef可以嵌套定义
typedef int Integer;
 Integer i = -10;
typedef Integer MyInteger;

char names[2][10] = {"jack","rose"};
char *names[2] = {"jack","rose"};

//类方法中不能访问成员变量(实例变量)
//使用场合:当方法内部不需要使用到成员变量时,就可以改为类方法
//可以允许类方法和对象方法同名


//()取值
int age = 19;
@(age);//age为nsnumber
                            
@28;
@23.3;//把double型转为double对象
@YES;
@"a"; //字符串 对象
@'a'; //char类型的对象

//完整地写一个类:类的声明和实现

[行为执行者 行为名称]
[类名 new];//创建一个新对象

//int a = (int)1.22
Animal *aa =[Dog new];
Dog *dd = (Dog *)aa ;  //Dog *dd = aa //编译器警告

//c语言字符串和oc字符串互转
 NSString *s = [NSString stringWithUTF8String:"chen"];
const char *c = [s UTF8String];

self的用途:
 1> 谁调用了当前方法,self就代表谁
 * self出现在对象方法中,self就代表对象
 * self出现在类方法中,self就代表类
 2> 在对象方法利用"self->成员变量名"访问当前对象内部的成员变量
 
3> [self 方法名]可以调用其他对象方法\类方法//???

A//方法是描述类的行为
{
    int _age;//成员变量---->的作用是描述类的状态
    int _no;
}
B : A
{
    int _weight;
}
// 继承:xx 是 xxx
// 组合:xxx 拥有 xxx

2.组合
A
{
    int _age;
    int _no;
}
B
{
    A *_a;
    int _weight;
}

super的作用:
    1.直接调用父类中的某个方法
    2.super处在对象方法中,那么就会调用父类的对象方法
      super处在类方法中,那么就会调用父类的类方法
    3.使用场合:子类重写父类的方法时想保留父类的一些行为

多态:
 1.没有继承就没有多态
 2.代码的体现:父类类型的指针指向子类对象
 3.好处:如果函数\方法参数中使用的是父类类型,可以传入父类、子类对象
 4.局限性:
 1> 父类类型的变量 不能 直接调用子类特有的方法。必须强转为子类类型变量后,才能直接调用子类特有的方法


重写-init方法
- (id)init
{
    // 1.一定要调用回super的init方法:初始化父类中声明的一些成员变量和其他属性
    self = [super init]; //self 当前对象
    // 2.如果对象初始化成功,才有必要进行接下来的初始化
    if (self != nil)
    { // 初始化成功
        _age = 10;
    }
    // 3.返回一个已经初始化完毕的对象
    return self;
}

// 父类的属性交给父类方法去处理,子类方法处理子类自己的属性
- (id)initWithName:(NSString *)name andAge:(int)age andNo:(int)no
{
    // 将name、age传递到父类方法中进行初始化
    if ( self = [super initWithName:name andAge:age])
    {
        _no = no;
    }
    return self;
}

@property int age ;
//- (void)setAge:(int)age ;
//- (int)age;
@synthesize age = _age;

id == NSObject *
// 万能指针,能指向/操作任何oc对象
id类型的定义
typedef struct objc object{
    class isa;
}*id;

/*
 分类的作用:在不改变原来类内容的基础上,可以为类增加一些方法
 使用注意:
 1.分类只能增加方法,不能增加成员变量
 2.分类方法实现中可以访问原来类中声明的成员变量
 3.分类可以重新实现原来类中的方法,但是会覆盖掉原来的方法,会导致原来的方法没法再使用
 4.方法调用的优先级:分类(最后参与编译的分类优先) --> 原来类  --> 父类
 */

// 取出i这个位置对应的字符
unichar c = [self characterAtIndex:i];


/*
 1.当程序启动时,就会加载项目中所有的类和分类,而且加载后会调用每个类和分类的+load方法。只会调用一次。
 
 2.当第一次使用某个类时,就会调用当前类的+initialize方法
 
 3.先加载父类,再加载子类(先调用父类的+load方法,再调用子类的+load方法)
 先初始化父类,再初始化子类(先调用父类的+initialize方法,再调用子类的+initialize方法)
 */

/*
 SEL其实是对方法的一种包装,将方法包装成一个SEL类型的数据,去找对应的方法地址。找到方法地址就可以调用方法
SEL:全称selector  表示方法的存储位置
 其实消息就是SEL
 */


重写description的类方法//实现打印对象的所有属性,默认打印<类名 :内存地址>
+ (NSString *)description
{
    return [NSString stringWithFormat:@"age=%@,name=%@",_age,_name];
}

调用方法
[p test];
[p performSeletor :@selector(test)];
[p performSeletor :@selector(test:) withBbject:@"123"];//test后面有:


sel s =@selector(test:);//定义一个sel的数据
 NSString *name = @"test2";
SEL s = NSSelectorFromString(name);
[p performSelector:s];

- (void)test2
{
    _cmd == @selector(test2);//_cmd调表当前方法
    NSString *str=NSStringFromSelector(_cmd);
    nslog(@"调用了test2方法--%@",str);
}
---》输出结果 :调用了test2方法--test2

//分类引入
#import "NSObject+ClassName.h"
//分类声明
@interface NSObject (ClassName)
@end
//分类方法实现
@implementation NSObject (className)
- (void)outPutClassName
{
    NSLog(@"%@",self);//self代表调用方法的对象
}
+ (void)outPutClassName
{
    NSLog(@"%@",[self class]);//调用class方法生成类
}
@end

/*
 1.方法的基本使用
 1> retain :计数器+1,会返回对象本身
 2> release :计数器-1,没有返回值
 3> retainCount :获取当前的计数器
 4> dealloc
 * 当一个对象要被回收的时候,就会调用
 * 一定要调用[super dealloc],这句调用要放在最后面
 
 2.概念
 1> 僵尸对象 :所占用内存已经被回收的对象,僵尸对象不能再使用
 2> 野指针 :指向僵尸对象(不可用内存)的指针,给野指针发送消息会报错(EXC_BAD_ACCESS)
 3> 空指针 :没有指向任何东西的指针(存储的东西是nil、NULL、0),给空指针发送消息不会报错
 */

 1.你想使用(占用)某个对象,就应该让对象的计数器+1(让对象做一次retain操作)
 2.你不想再使用(占用)某个对象,就应该让对象的计数器-1(让对象做一次release)
 3.谁retain,谁release
 4.谁alloc,谁release

/*
 _speed :直接访问成员变量
 self->_speed :直接访问成员变量
 self.speed : get方法
 [self speed] : get方法
 */

_book = [book retain];//person中的setBook
- (void)dealloc//person中的dealloc
{
    [_book release];
    NSLog(@"person被回收");
    [super dealloc];
}

 内存管理代码规范:
 1.只要调用了alloc,必须有release(autorelease)
 对象不是通过alloc产生的,就不需要release
 2.set方法的代码规范
 1> 基本数据类型:直接复制
 - (void)setAge:(int)age
 {
     _age = age;
 }
 2> OC对象类型
 - (void)setCar:(Car *)car
 {
     // 1.先判断是不是新传进来对象
     if ( car != _car )
     {
         // 2.对旧对象做一次release
         [_car release];
         // 3.对新对象做一次retain
         _car = [car retain];
     }
 }
 
 3.dealloc方法的代码规范
      1> 一定要[super dealloc],而且放到最后面
      2> 对self(当前)所拥有的其他对象做一次release
       - (void)dealloc
       {
           [_car release];
           [super dealloc];
       }

// retain : 生成的set方法里面,release旧值,retain新值
@property (retain) Book *book;


/*
 1.set方法内存管理相关的参数
 * retain : release旧值,retain新值(适用于OC对象类型)
 * assign : 直接赋值(默认,适用于非OC对象类型)
 * copy   : release旧值,copy新值
 
 2.是否要生成set方法
 * readwrite : 同时生成setter和getter的声明、实现(默认)
 * readonly  : 只会生成getter的声明、实现
 
 3.多线程管理
 * nonatomic : 性能高 (一般就用这个)
 * atomic    : 性能低(默认)
 
 4.setter和getter方法的名称
 * setter : 决定了set方法的名称,一定要有个冒号 :
 * getter : 决定了get方法的名称(一般用在BOOL类型)
 * @property (getter = isRich) BOOL rich;//设值bool值
 */

                            
 1.@class的作用:仅仅告诉编译器,某个名称是一个类
    @class Person; //仅仅告诉编译器,Person是一个类
 
 2.开发中引用一个类的规范
 1> 在.h文件中用@class来声明类
 2> 在.m文件中用#import来包含类的所有东西
 
 3.两端循环引用解决方案
 1> 一端用retain
 2> 一端用assign
 
/*
 1.autorelease的基本用法
 1> 会将对象放到一个自动释放池中
 2> 当自动释放池被销毁时,会对池子里面的所有对象做一次release操作
 3> 会返回对象本身
 4> 调用完autorelease方法后,对象的计数器不变
 
 2.autorelease的好处
 1> 不用再关心对象释放的时间
 2> 不用再关心什么时候调用release
 
 3.autorelease的使用注意
 1> 占用内存较大的对象不要随便使用autorelease
 2> 占用内存较小的对象使用autorelease,没有太大影响
 
 4.错误写法
 1> alloc之后调用了autorelease,又调用release
 2> 连续调用多次autorelease
 
 5.自动释放池
 1> 在iOS程序运行过程中,会创建无数个池子。这些池子都是以栈结构存在(先进后出)
 2> 当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池
 
 6.自动释放池的创建方式
 1> iOS 5.0前
 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 [pool release]; // [pool drain];
 2> iOS 5.0 开始
 @autoreleasepool
 {
 
 }
 */

 1.系统自带的方法里面没有包含alloc、new、copy,说明返回的对象都是autorelease的
 
 2.开发中经常会提供一些类方法,快速创建一个已经autorelease过的对象
 1> 创建对象时不要直接用类名,一般用self
 + (id)person
 {
 return [[[self alloc] init] autorelease];
 }


/*
 ARC的判断准则:只要没有强指针指向对象,就会释放对象
 
 1.ARC特点
 1> 不允许调用release、retain、retainCount
 2> 允许重写dealloc,但是不允许调用[super dealloc]
 3> @property的参数
 * strong(retain) :成员变量是强指针(适用于OC对象类型)
 * weak :成员变量是弱指针(适用于OC对象类型)
 * assign : 适用于非OC对象类型
 * copy   : release旧值,copy新值
 4> 以前的retain改为用strong
 
 指针分2种:
 1> 强指针:默认情况下,所有的指针都是强指针 __strong
 2> 弱指针:__weak
    分别在两个文件的.h文件中写@class Dog; @class Person;
 
 当两端循环引用的时候,解决方案:
 1> ARC
 1端用strong,另1端用weak
 
 2> 非ARC
 1端用retain,另1端用assign
 */


 block要掌握的东西
 1> 如何定义block变量
 int (^sumBlock)(int, int);
 void (^myBlock)();
 2> 如何利用block封装代码
 ^(int a, int b) {
 return a - b;
 };
 
 ^() {
 NSLog(@"----------");
 };
 
 ^ {
 NSLog(@"----------");
 };
 
 3> block访问外面变量
 * block内部可以访问外面的变量
 * 默认情况下,block内部不能修改外面的局部变量
 * 给局部变量加上__block关键字,这个局部变量就可以在block内部修改
 
 4> 利用typedef定义block类型
 typedef int (^MyBlock)(int, int);
 // 以后就可以利用MyBlock这种类型来定义block变量
 MyBlock block;
 MyBlock b1, b2;
 
 b1 = ^(int a, int b) {
 return a - b;
 };
 
// 给局部变量加上__block关键字,这个局部变量就可以在block内部修改
 // block用来保存一段代码
 // block的标志:^
 /*
 block跟函数很像:
 1.可以保存代码
 2.有返回值
 3.有形参
 4.调用方式一样
 */

定义block变量
/*
 void (^myblock)() = ^(){
 NSLog(@"----------------");
 NSLog(@"----------------");
 };*/

/*
 1.协议的定义
 @protocol 协议名称 <NSObject>
 // 方法声明列表....
 @end
 
 2.如何遵守协议
 1> 类遵守协议
 @interface 类名 : 父类名 <协议名称1, 协议名称2>
 @end
 2> 协议遵守协议
 @protocol 协议名称 <其他协议名称1, 其他协议名称2>
 @end
 
 3.协议中方法声明的关键字
 1> @required (默认)
 要求实现,如果没有实现,会发出警告
 2> @optional
 不要求实现,怎样不会有警告
 
 4.定义一个变量的时候,限制这个变量保存的对象遵守某个协议
 类名<协议名称> *变量名;
 id<协议名称> 变量名;
 NSObject<MyProtocol> *obj;
 id<MyProtocol> obj2;
 如果没有遵守对应的协议,编译器会警告
 
 5.@property中声明的属性也可用做一个遵守协议的限制
 @property (nonatomic, strong) 类名<协议名称> *属性名;
 @property (nonatomic, strong) id<协议名称> 属性名;
 
 @property (nonatomic, strong) Dog<MyProtocol> *dog;
 @property (nonatomic, strong) id<MyProtocol> dog2;
 
 6.协议可用定义在单独.h文件中,也可用定义在某个类中
 1> 如果这个协议只用在某个类中,应该把协议定义在该类中
 2> 如果这个协议用在很多类中,就应该定义在单独文件中
 
 7.分类可用定义在单独.h和.m文件中,也可用定义在原来类中
 1> 一般情况下,都是定义在单独文件
 2> 定义在原来类中的分类,只要求能看懂语法
 */



 NSRange(location length)
 NSPoint\CGPoint
 NSSize\CGSize
 NSRect\CGRect (CGPint CGSize)
 

// 使用这些CGPointEqualToPoint、CGRectContainsPoint等函数的前提是添加CoreGraphics框架
typedef struct _QFposition{
    int row,
    int column
};
_QFposition  _postion;//定义

NSRange r1 = {2,3};
NSRange r2 = {.location = 2,.length = 2};
NSRange r3 = NSMakeRange(2, 4);

CGPoint p1 = NSMakePoint(12, 14);
NSPoint p2 = CGPointMake(12, 14);

NSSize s1= CGSizeMake(-1, -1);
NSSize s2 = NSMakeSize(2, 4);
CGSize s3 = NSMakeSize(2, 3);
CGSize s4 = CGSizeMake(2, 3);

CGRect r1= CGRectMake(0, 0, 2, 3);
CGRect r2 ={{0,0},{100,23}};
CGRect r3 = {p1,s2};
// 使用CGPointZero等的前提是添加CoreGraphics框架
CGRect r4 = {CGPointZero,s2};

BOOL b2 = CGRectContainsPoint(CGRectMake(50, 40, 100, 50), CGPointMake(60, 45));

[array enumerateObjectsUsingBlock:
 // 每遍历到一个元素,就会调用一次block
 // 并且当前元素和索引位置当做参数传给block
    ^(id obj, NSUInteger idx, BOOL *stop)
    {
        NSLog(@"%ld - %@", idx, obj);
        if (idx == 0)
            {
                *stop = YES;// 停止遍历
            }
    }
 ];

/*
 NSSet和NSArray的对比
 1> 共同点
 * 都是集合,都能存放多个OC对象
 * 只能存放OC对象,不能存放非OC对象类型(基本数据类型:int、char、float等,结构体,枚举)
 * 本身都不可变,都有一个可变的子类
 
 2> 不同点
 * NSArray有顺序,NSSet没有顺序
 NSString *str1 =  [s2 anyObject];//随机拿出一个元素
 */

 集合
 1.NSArray\NSMutableArray
 * 有序
 * 快速创建(不可变):@[obj1, obj2, obj3]
 * 快速访问元素:数组名[i]
 
 2.NSSet\NSMutableSet
 * 无序
 
 3.NSDictionary\NSMutableDictionary
 * 无序
 * 快速创建(不可变):@{key1 : value1,  key2 : value2}
 * 快速访问元素:字典名[key]
 
/*
 字典:
 key ----> value
 索引 ----> 文字内容
 里面存储的东西都是键值对
 */

// @20  将 20包装成一个NSNumber对像
// 将age变量包装成NSNumber对象
int age = 100;
@(age);
//[NSNumber numberWithInt:age];

// 结构体--->OC对象
CGPoint p = CGPointMake(10, 10);
// 将结构体转为Value对象
NSValue *value = [NSValue valueWithPoint:p];
// 将value转为对应的结构体
// [value pointValue];
NSArray *array = @[value ]
 [ i stringVilue];


点语法,@property 和@synthesize 是成对出现的
//@property 是声明set和get方法
//@synthesize 是实现set和get方法


//把一个结构体转化为对象 NSvalue 存储到NSarray中
typedef struct Person
{
    int age,
    float height
}Person;
Person zhangshang = {18,1.77};
//作用:把c的类型的数据转化为NSvalve类型
//参数1 :数组的地址
//参数2 :数组的类型
//@encode作用是把类型转化为字符串
NSValue *value =[ [NSValue alloc]initWithBytes:&zhangshang objCType:@encode(Person)];
NSMutableArray *marr = [[NSMutableArray alloc]init];
[marr addObject:value];

Person newperson;
//从nsvalue转换出存储的数据
[value getValue:&newperson];
NSLog(@"%d---%f",newperson.age,newperson.height);
}


//copy把传入的字符串拷贝一份新的(字符串,字典,数组)
@property (copy)  NSString *type;
//assign表示直接赋值,不retain也不copy(默认)
@property (assign) float price;
//retain表示实现的setter和getter中添加retain
@property (retain)Engine *engine;

//代理的属性修饰符必须是assgin。不能是retain,否则会引起无法释放的问题
@property (assign) id delegate;

 //类中对象指针一般在init中申请对象,在dealloc中释放对象

NSMutableString *name = [[NSMutableString alloc]initWithString:@"ling er"];
//问题 ---->两个指针,只有一个对象
  //copy返回不可变对象, ,mutablestring返回可变对象
NSMutableString *pName = [name mutableCopy];
name.string = @"er ling";
NSLog(@"pName = %@",pName);


//类方法创建的字符串对象,无需释放,自动释放。通过alloc创建的字符串对象需要release
//对象加入到数组中
//数组会对持有之中对象,数组会给每个加入他得对象发送retain消息

NSString *strw = @"2323";
NSLog(@"%lu",strw.retainCount);//18446744073709551615
NSString *st = [[NSString alloc]initWithString:strw];//18446744073709551615
NSLog(@"%lu",st.retainCount);
NSString *st1 = [[NSString alloc]initWithFormat:@"%@",strw];
NSLog(@"%lu",st1.retainCount);//1


//以alloc创建的字符串最后使用release释放
//以类方法和字符串常量创建的字符串不需要释放
NSString *str1 = [[NSString alloc]initWithUTF8String:"123"];
NSLog(@"'1 = %lu",str1.retainCount);//1

NSString *str2 = [[NSString alloc]initWithString:@"2345"];
NSLog(@"2 = %lu",str2.retainCount);//18446744073709551615

//如何利用协议实现不同对象的排序(c语言:冒泡,快排,选择)
//oc中nsarray用sortUseingSelector
[marr sortUsingSelector:@selector(myCompare:)];
for (id obj in marr) {
    [obj showMe];
}

//类别/分类(category)---->给某个类添加方法
@interface NSMutableString (Extension)
- (void)reverserString;
@end
@implementation NSMutableString (Extension)
- (void)reverserString
{}//增加单词逆转功能
@end

//协议(protocol)---->强制性让某个对象拥有某方法
@protocol MyProtocol <NSObject>
- (void)sayHello;
@end
//遵守一个协议(先引入,后在类的后天添加,可以不声明协议的方法,但必须实现)
#import "MyProtocol.h"
@interface Test : NSObject <MyProtocol>
- (void)show;
@end

//一般,哪个对象给其他对象发送消息,这个对象指定协议(规范:xxxxDelegate)











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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值