OC语法


返回值是BOOL类型的 方法名一般都是is开头


编译只检测语法错误


方法声明可以重复 方法的实现不可以重复


自己的.m文件要包含自己的.h文件



定义一个类分2个文件 .h声明文件 .m实现文件

.h : 成员变量 方法的声明

.m : 方法的实现


如果想使用某一个类,只需要#import类的.h文件即可



类的设计:

1> 类名

//类名第一个字母必须大写

//不能有下划线

//多个英文字母用驼峰标识(JumpZoombie

2> 属性

3> 行为(功能)





//完整的写一个函数:函数的声明和定义(实现)

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


//1.类的声明

//声明对象的属性和行为

//: NSObject  目的是:让Car这个类具备创建对象的能力


//因为使用了NSObject

@import <Fundation\Fundation.h>


@interface Car : NSObject 

{//用来声明对象属性(实力变量\成员变量,默认会初始化为0

    @public

    //@public可以让外部的指针间接访问对象内部的成员变量

    int wheels;

    int speed; 

}

//方法(行为):方法名,参数, 返回值(声明 实现)

//只要是OC对象的方法,必须以减号-开头

//OC方法中任何数据类型都必须用小括号()括住

//OC方法中的的小括号()只有一个作用:括住数据类型

- (void)run;  //申明方法


@end



//2.类的实现

//用来实现@interface中声明的方法

@implementation Car

//方法的实现(说清楚方法里面有什么代码)


- (void)run

{

    NSlog(@"车子跑起来了");

}


@end


int main()

{

     //OC中,想执行一些行为,就写上一个中括号[行为执行着 行为名称]

     //利用类来创建对象

     //执行Car这个类的行为来创建对象


     //定义了一个指针变量pp将来指向的是Car类型的对象

     //[Car new]会创建一个新对象,并且会返回新对象本身(新对象的地址)

    Car *p = [Car new];

      

    Car *p2 = [Car new];

    //p所指的对象的wheels属性赋值

    p->wheels = 4;

    p->speed = 250;

    p2->wheels = 5;

    p2->speed = 300;

    //p所指向对象发送一条run消息

    [p run];

    [p2 run];


    NSlog(@"车子有%d个轮子,时速为:%dkm/h", p->wheels, p2->speed);

    

    return 0;

}


NSString * str1 = @"hello world";


NSString * str2 = [[NSString alloc] initWithString:@"hello world"];


NSString * str3 = [[NSString alloc] initWithUTF8String:"hello world"];

//C的字符串创建OC的字符串对象


NSString * str4 = [[NSString  alloc] initWithFormat:@"hello %d %c", 5, 'A'];

//使用格式符,拼接成一个字符串


[str2 release];

[str3 release];

[str4 release];



//申请临时字符串对象(不需要手动释放)

NSString * str5 = [NSString stringWithUTF8String:"hello world"];


NSString * str6 = [NSString stringWithFormat:@"%d %@ %c", 1, @"hello", 'R'];


NSString * str7 = [NSString stringWithString:str1];


多态(对于对象  继承而言):父类指针指向子类对象


调用方法时会动态检测对象的真实类型


子类对象的类型也是父类这个类型


1.没有继承就没有多态

2.代码的体现:父类类型的指针指向子类对象

3.如果参数中使用的是父类类型 可以传入父类,子类的对象


多态局限性:父类类型的指针变量不能用来调用子类特有的方法

(必须强转为子类类型变量后 才能直接调用子类特有的方法)


super的作用:

1.直接调用父类中的方法

2.super处在对象方法中 那么就会调用父类中的对象方法

  super处在类方法中,那么就会调用父类的类方法

3.使用场合: 子类重写父类的方法时想保留父类的一些行为


重写:子类重新实现父类中的的某个方法,覆盖父类以前的做法


父类必须声明在子类的前面

子类不能拥有父类相同的成员变量

调用某个方法优先去当前类中找 如果找不到 去父类找


继承使用场合:当两个类拥有相同属性和方法的时候 就可以将相同的东西抽取到一个父类中

                            A类完全拥有B类的部分属性和方法时 可以考虑让B类继承A

组合:xxx拥有xxx

继承:xxxxxx




NSObject 含有isa成员变量 retaincount成员变量


断点调试

isa(成员变量)指向这个类

没有成员变量的方法尽量使用类方法

#pragma mark  标记 注释



点语法本质是set\get方法的调用(编译进行)(只要修改了类中成员变量的值就可以使用点语法)

 类方法不能访问成员变量(类方法没有对象 没有对象就没有成员变量)



成员变量的作用域:


@public

任意地方都能直接(通过变量名)访问成员变量

@private

只能在当前类的对象方法中访问

@protected

能在当前类和子类中的对象方法直接访问成员变量


系统默认为@protected


在实现中写成员变量则默认为是私有的 不能和声明中的成员变量重名


OC中是单继承 父类也叫子类(superclass


@property@synthesize


编译器特性:

@propery可以自动生成get set 声明

例如:

@property int age;相当于


- (void)setAge:(int)age;

-(void)age;


@property NSString *name;相当于


- (void)setName:(NSString *)name;

- (NSString)name;


@synthesize 可以自动生成get set 实现


@synthesize age = _age;相当于


- (void)setAge:(int)age

{

    _age = age;

}

- (int)age

{

    return _age;

}


get方法set方法:

方法声明:

@property int  speed;

@property int  wheels;

方法的实现:

@synthesize speed = _speed;

@synthesize wheels = _wheels;


注: 

如果在类的声明中只写:@property int age;

编译器会做三件事:1.自动生成成员变量_age@private类型)

                                    2.自动生成_ageset get方法的声明

                                    3.自动生成_ageset get方法的实现


// assign直接赋值 (默认是assign)

// readonly 只生成get方法 不生成set方法

// readwrite 同时生成set get方法(默认是readwrite

// atomic 原子性访问(默认)考虑线程安全

// nonatomic 非原子性访问

// 属性修饰符setter=setNo:, getter=no 修改方法名 调用可以使用两套 指向同一个成员变量_number

@property (assign, readwrite, atomic, setter=setNo:, getter=no) long number;



id是一种类型(万能指针包括* 可以指向\操作任何OC对象)

id  ==== NSObject *


构造方法(用来初始化对象的方法):


NSObject里的构造方法

- (id)init

{

isa = [ self class];

return self;

}


完整的创建一个可用的对象[Person new]有两步 

1.分配存储空间  + alloc

2.初始化               - init


//[super init]  初始化父类的成员变量

- (id) init // 重写Init方法

{

if (self = [super init])

{

_age =10;

}

return self;

}


重写构造方法的目的:为了让对象创建出来成员变量就会有一些固定的值

注意点:

1.先调用父类的构造方法([super  init]

2.再进行子类内部成员变量的初始化


自定义构造方法:

- (id)initWithName:(NSString *)name;

- (id)initWithName:(NSString *)name

{

if (self = [super init])

{

_name = name;

}

return self;

}


分类 Category (只能增加方法 不能增加成员变量)(可以给某一个扩充一些方法(不修改原来类的代码))

category用于向已经存在的类添加方法以达到扩展已有类的目的。

一般类别有4种用途:

1 不继承情况下对已有类扩展

2 简化类的开发工作(多人分类别开发一个类)

3 将常用的相关方法分组

4 没有源码情况下添加(重写)方法。


//声明

@interface NSString (inverse);

@end

// 实现

@implement NSString (inverse)

@end


不同的人写不同的分类(模块)

用这个类声明的对象就可以使用不同的人写的方法

分类的方法实现中可以访问原类的成员变量

分类可以重新实现原来类的方法 但是会覆盖掉原来类的方法 原来类的方法永远失效


方法寻找的优先级:分类方法名与原类方法名重复与父类方法名重复

 优先去找分类的方法 再找原类的方法 再找父类的方法

如果不同分类的方法重名 则看编译顺序 选择实现最后参与编译的文件


类的本质:

类本身也是个对象 是个class类型的对象 简称类对象


利用实例对象获取内存中的类对象

Person * p = [[Person alloc] init];

class c = [p class];

class c1 = [person class];

//c = c1 类型是Person

// Person *p1 = [c new]; // 利用这个Person类(c)创建一个Person对象


load:

//当程序启动的时候 就会加载项目中的所有类和分类 类加载完毕后就会调用每个类和分类的+load方法 只会调用一次

注:先加载父类再加载子类(分类也会加载 原始类后加载)

+ (void)load

{

NSLog(@“person-load”);

}

initialize:

//当第一次使用这个类的时候(初始化) 就会调用一次当前类的+initialize方法

+ (void)initialize

{

// 可以用来监听 类第一次使用时(初始化)会给与提示

NSLog(@“person-initialize”);

}


description:用于对象的描述

NSObject自带的方法(既有类方法又有对象方法)返回值是OC字符串

对象方法默认取对象的地址 结果:<类名 :内存地址>

类方法默认取对象的类名

还可以自己重写(最好写对象方法)


NSLog(@“%d”, _LINE_); // 打印当前函数

printf(“%s\n”, _FILE_); // 打印当前路径

NSLog(@“%s”, _func_); // 打印当前函数名


SEL(存放方法地址)(其实消息就是SEL

每个方法里都有:SEL  _cmd;

_cmd 存放该方法的地址

//_cmd == @selector(test)


Person *p = [[Person alloc] init];


[p performSelector:@selector(方法名)]; // 相当于[p test];


[p test];  

// 1.test方法包装成SEL类型的数据

// 2.根据SEL数据找到对应的方法地址

// 3.根据方法地址调用对应的方法


内存管理:(相对于堆里面的数据而言)(对于基本类型int char float double struct enum无效)


每个对象都存放4字节的引用计数器(记录对象被引用的个数 整数)

当计数器等于0对象就会被销毁(内存回收)

对象刚诞生的时候引用计数器默认为1

如果对象计数器不为0 那么在整个程序运行的过程中 它占用的内存就不可能被回收 除非整个程序已经退出


引用计数器的一些方法:

1,当给对象发送一条retain消息 可以使引用计数器+1retain方法返回对象本身

2,当给对象发送一条release消息 可以使引用计数器-1

3,可以给对象发送retainCount消息获得当前的引用计数器值


当一个对象被销毁时 系统会自动向对象发送一条dealloc消息

一般会重写dealloc方法 在这里释放相关资源 dealloc就像对象的遗言

注:

一旦重写了dealloc方法 就必须调用[super dealloc]

并且放在最后面调用

不能直接调用dealloc方法


概念:

1.僵尸对象:被释放(回收)的在内存中不存在的对象 僵尸对象不能再使用

2.野指针:指向僵尸对象(不可用内存)的指针 给野指针发送消息会报错

EXC_BAD_ACCESS(野指针错误)访问了一块坏的内存(已经被回收,已经不可用的指针)

3.空指针:没有指向任何东西的指针(存储的东西是nil NULL 0

OC中不存在空指针错误 给空指针发送消息 不报错

 

只要还有人在用某个对象 那么这个对象就不会被回收

只要你想用这个对象 就让对象的计数器+1

当你不再使用这个对象时 就让对象的计数器-1


1.谁创建 release

如果你通过alloc new [Mutable]copy来创建一个对象 那么你必须调用releaseautorelease

换句话说 不是你创建的 就不用你去[auto]release

2.retain release

只要你调用了retain 无论这个对象是如何生成的 你都要调用release

3.有始有终 有加就有减

曾经让对象计数器加一 最后就要让对象计数器减一


总结:内存管理代码规范:

.只要调用alloc 必须有release(autorelease)  如果对象不是alloc产生的就不需要release


.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];

}

}


.dealloc方法的代码规范

1>一定要[super dealloc], 而且放在最后面

2>self(当前)所拥有的其他对象做一次release


- (void)dealloc

{

[_car release];

NSLog(@“某对象被释放!”);

[super dealloc];

}


// retain: 在生成set的方法里面release旧值,retain新值

@property (retain) NSString *name

 

property里面的参数

1.内存管理的参数

retainrelease旧值,retain新值(适用于OC对象类型)

assign: 直接赋值(默认, 适用于非OC对象类型)

copy: release旧值,copy新值


2.是否要生成set方法

readonly:只会生成get的声明和实现

readwrite:同时生成get set的声明和实现(默认)


3.多线程管理

nonatomic: 性能高(一般就用这个)

atomic: 性能低(默认)


4.set get方法的名称

setter: 决定了set方法的名称 一定要有个冒号

getter: 决定了get方法的名称


copy 不管是可变还是不可变的copy都会生成不可变对象(不可变对象调用copy方法为浅拷贝)

mutableCopy 不管是可变还是不可变的mutableCopy都会生成可变对象(深拷贝)


@class的作用(避免循环引用):仅仅告诉编译器 某个名称是一个类

开发中引用一个类的规范

1>.h文件中用@class来声明类

2>.m文件中用#import来包含类的所有东西


(循环引用)解决方案:

1> 一端retain

2> 一端assign


autorelease的基本用法(对象方法 返回对象本身 延迟了对象释放的时间)

1> 会将对象放到一个自动释放池()

2> 当自动释放池被销毁时 会对池子里面的所有对象做一次release操作

3> 会返回对象本身

4>调用完autorelease方法后 对象的计数器不变


autorelease的好处

1> 不用再关心对象的释放时间

2> 不用再关心什么时候调用release


autorelease的使用注意点

1> 占用内存较大的对象不要随便使用autorelease

2> 占用内存较小的对象使用autorelease 没有太大影响 


autorelease的错误写法

1>alloc之后调用了autorelease 又调用release

2>连续调用多次autorelease


自动释放池

1>iOS程序运行过程中 会创建无数个池子 这些池子都是以栈结构存在(先进后出)

2>当一个对象调用autorelease方法时 会将这个对象放到栈顶的释放池


自动释放池的创建方式:

@autoreleasepool // 可以无限多的创建和嵌套

{ //开始代表创建了释放池


} // 结束代表销毁释放池(推荐)


NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; //开始代表创建了释放池

Person *p = [[[Person alloc] init] autorelease];

[pool release]; // 结束代表销毁释放池(淘汰)


1.开发过程中一般使用一个类方法快速创建一个对象 return [[[Person alloc] init] autorelease];  // 申请一个对象并放入释放池 即返回一个autorelease的对象)

创建对象时不要直接用类名 一般用self

2.系统自带的方法里面没有包含 alloc new copy 说明返回的对象都是autorelease


ARC  自动内存管理(编译器特性)

MRC 手动内存管理


ARC的判断的准则:只要没有强指针指向对象 就会释放对象 

指针分2种:

1>强指针:默认情况下 所有的指针都是强指针 (关键字:__strong 修饰指针它就是强指针)

2>弱指针:(关键字:__weak 修饰指针它就是弱指针)


@property (nonatomic, strong) Dog *dog;


ARC特点:

1>不允许调用release retain retainCount

2>允许重写dealloc 但是不允许调用[super dealloc]

3>@property的参数

* strong: 成员变量是强指针 相当于原来的retain(适用于OC对象类型)

*weak:成员变量是弱指针 相当于原来的assign(适用于OC对象类型)

*assign:适用于非OC对象类型

4>以前的retain 改为 strong


-fno-objc-arc  ARC环境转为MRC

-f-objc-arc       MRC环境转为ARC


(循环引用)解决方案

1>一端strong

2>一端weak

#import <Foundation/Foundation.h>

@class Dog;

@interface Person : NSObject

@property (nonatomic, strong) Dog * dog;

@end


#import <Foundation/Foundation.h>

@class Person;

@interface Dog : NSObject

@property (nonatomic, weak) Person *person;

@end


Block(一种数据类型) 封装了一段代码 可以在任何时候执行

Block 可以作为函数参数或者函数的返回值 而其本身又可以带输入参数或返回值

苹果官方建议尽量多用block 在多线程 异步任务 集合遍历 集合排序 动画转场用的很多


定义block变量:

// 没有返回值 没有形参

void (^myBlock)() = ^{

NSLog(@"------");

};

myblock(); 


// 有返回值 有形参

int (^sumBlock)(int, int) = ^(int a, int b){

return a + b;

};

int c= sumblock(10,11);


// 利用typedef定义block类型

#import <Foundation/Foundation.h>

typedef int (*MyBlock)(int, int);

int main()

{

MyBlock sumBlock;

sumBlock = ^(int a, int b){

return a + b;

};

MyBlock minusBlock = ^(int a, int b){

return a - b;

};

NSLog(@"%d %d", sumBlock(10,9), minusBlock(10,9));

return 0;

}


block访问外面局部变量

* block内部可以访问外面的变量

* 默认情况下 block内部不能修改外面的局部变量

* 给局部变量加上__block关键字 这个局部变量就可以在block内部修改


@protocol (协议)

它可以让你轻松的定制一个中心对象周围其他几个对象的行为。监听某个对象的变化


基本用途:

可以用来声明一大堆方法(不能声明成员变量)

只要某个类遵守了这个协议 就相当于拥有这个协议中的所有方法的声明

只要父类遵守了某个协议 就相当于子类也遵守了

一个协议遵守了另外一个协议 就可以拥有另一个协议的所有方法声明


格式:

1>协议的编写

@protocol 协议名称 <NSObject>

@property (nonatomic, copy) NSString * name; // 声明一个属性

+ (…)…  // 声明一个类方法

@required  要求实现(默认) 不实现就会发出警告

// 方法声明列表

@optional  不要求实现 怎样都不会警告

// 方法声明列表

@end


2>某个类遵守协议

@interface 类名 :父类名 <协议名称1,协议名称2>

@end


3>协议遵守协议

@protocol 协议名称 <其他协议名称1 其它协议名称2>

@end


4>定义一个变量的时候 限制这个变量保存的对象遵守某个协议

类名<协议名称> *变量名;

id<协议名称> 变量名

例:

NSObject<myProtocol> *obj;

id<myProtocol> obj2;

如果没有遵守对应的协议 编译器会警告(严重警告)


5>@property中声明的属性也可以用作一个遵守一个协议的限制

@property (nonatomic, strong) 类名<协议名称> *属性名;


6>协议可以定义在单独的.h文件中 也可以定义在某个类中

1. 如果这个协议只用在某个类中 应该把协议定义在该类中

2.如果这个协议用在很多类中 就应该定义在单独文件中


7>分类可以定义在单独.h文件中 也可以定义在原来类中

1. 一般情况下 都是定义在单独文件

2. 定义在原来类中的分类 只要求能看懂语法


Foundation框架:


集合:Array set dictionary


NSRange(location , length)

NSMakeRange(location length)

找不到 length = NSNotFound = -1


NSPoint\CGPoint

CGpoint p1 = NSMakePoint(10,10);

NSPoint p2 = CGPointMake(20,20); // 常用

CGPointMake(0,0) == CGPonitZero // 表示原点


NSSize\CGSize

NSSize s1 = CGSizeMake(100,50); // 常用

CGSize s2 = NSMakeSize(200,60);

CGSizeMake(0,0) == CGSizeZero 


NSRect\CGRect

CGRect r1 = CGRectMake(0, 0, 100, 50);

CGRect r2 = {{0, 0},{100,90}};

CGRect r3 = {p1, s1};

CGRectMake({0,0},{0,0}) == CGRectZero


NSString\NSMutableString

NSUTF8StringEncoding 用到中文就可以用这种编码

URL:资源路径

网络资源:协议头://路径

本地资源:file://绝对路径(以/开头的才叫绝对路径)

NSURL *url = [[NSURL alloc] initWithString:@“  资源  ”];

NSError * error = nil;

    NSString * dicString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error];

    if (error) {

        NSLog(@"文件读取错误!");

    } // 读取path路径里的内容转化为OC字符串




NSArray\NSMutableArray (有序)

遍历:

#import <Foundation/Foundation.h>


int main(int argc, const char * argv[]) {

    @autoreleasepool {

        NSArray *array = @[@"1", @"2", @"3", @"4"];

        // Block代码块遍历数组

        [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

            NSLog(@"%ld-%@", idx, obj);

            // 停止遍历

            if (idx == 2) {

                *stop = YES;

            }

        }];

    }

    return 0;

}




NSDictionary\NSMutableDictionary (无序)

id obj = dict[@“key”]; // 取出对应键的值

只允许有一个key 可以有多个value



NSSet (无序)

NSSet *set = [NSSet setWithObject:….,nil];

id obj = [set anyObject]; // 随机拿出一个元素


NSNumber

@20 20包装成NSNumber对象(编译器特性)

int age = 10;   @(age) age变量包装成NSNumber对象


NSDate

y M d m s 

H(24)    h(12)

 




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值