自己学习中总结的 比较零散,见谅
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)