黑马程序员-OC的核心语法

------ Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
一.关键语法
1.点语法
点语法的本质还是方法调用
比如 p.age=10; 就是转换为 [p setAge:10];
 int a = p.age 转换为 int a = [p age];

2.成员变量作用域
    1.基本概念
        局部变量、全局变量都有自己的作用域,成员变量也不例外
2.类型
    >@private:只能在当前类的实现@implementation中直接访问
    >@protected:可以在当前类以及子类的实现@implementation中直接访问
    >@public:任何地方都可直接访问
    >@package:同一个“体系内”(框架)可以访问,介于@private@public之间
3.继承补充
    >专业术语 父类\超类 superclass 子类 subclass\subclasses 单继承
4.@implementation补充
    没有@interface,只有@implementaton,也可以开发一个类,在.m文件进行声明
    在声明里写的成员变量,默认是private
    实现里面也能写成员变量 默认是私有,因为不会被其他文件包含,无法改设置就算写上@public也没用
    (@interface)声明和(@implementation)实现里面不能定义同名的变量
5.成员变量的作用域
    @public:在作何地方都能直接方问对象的成员变量
    @private:只能在当前类的对象方法中直接访问(@implementation默认)
    @protected:可以在当前类及其子类的对象方法中直接访问(@interface默认)
    @package:只要处在同一个框架中,就能直接方问对象的成员变量
    @interface与@implementation中的成员变量不能同名
    子类与父类的成员变量不能同名
    
二.关键字
1.@property
    在@interface和@end之间
    编译器特性,当遇到@property int age自动生成某个成员变量的setter和getter声明,不能重复声明
    如果使用了@property,但是没有成员变量,则自动生成private类型的成员变量
    缺点,成员变量是死的,无法设置public或protected

2.@synthesize
    在@implementation和@end之间
    自动生用age的setter和getter的实现,并且会访问_age这个成员变量
    @synthesize age = _age;也可以@synthesize age = _age,name = _name;
    如果@synthesize age没有指定,那么默认访问和age一样的成员变量

3.@property新特性
    自从Xcode4.4以后,@property就独揽了@synthesize的功能,也不是说,@property可以同时声明成员变量的声明和实现
    @property(nonatomic,retain) UIWindow *window;  

    其中参数主要分为三类:
    读写属性: (readwrite/readonly)
    setter语意:(assign/retain/copy)
    原子性: (atomicity/nonatomic)

4.各参数意义如下:

    readwrite: 产生setter\getter方法
    readonly: 只产生简单的getter,没有setter。
    assign: 默认类型,setter方法直接赋值,而不进行retain操作
    retain: setter方法对参数进行release旧值,再retain新值。
    copy: setter方法进行Copy操作,与retain一样,不对旧值release
    nonatomic: 禁止多线程,变量保护,提高性能

5.id
    id是一种类似如 id d 所以变量名不能叫id,id是关键字
    id是万能指针,能指向\操作任何OC对象
    //id == NSObject *
    typedef struct objc_object{
        Class isa;
    }*id;
    //id后面不加*
    用id调用不存在的方法会报错

三.类的构造方法

1.new的用处
 完整地创建一个可用的对象
 1.分配存储空间 + alloc
 2.初始化 - init
 3.释放 - dealloc
Person *p3 = [[Person alloc] init];
 
2.构造方法:是用来初始化对象的方法,是对象方法 -开头
    重写构造方法的目的:为了让对象创建出来,成员变量就会有一些固定的值
    重写构造方法注意点
        1.先调用父类的构造方法([super init])
        2.再进行子类内部成员变量的初始化

    重写-init方法 - (id)init
        1.一定要调用回super的init方法:初始化父类中声明的一些成员变量和其他属性 self = [super init];//当前对象 self = [父类将isa初始化为当前类]
        2.当前对象指针指向父类构造出来的对象
        3.当前对象指针 self = [父类将isa初始化为当前类]

    init的执行过程,运行原理
    //子类实例被创建的时候会先创建父类实例(调用父类的无参数构造方法),然后再创建子类实例
    
    重写构造方法的执行顺序
     student init super init
     person init super init
     nsobject init ....被封闭了
     返回一个class

3.自定义构造函数规范
 1.一定是对象方法,一定以 - 开头
 2.返回值一般以id类型
 3.方法名一般以initWith开头
 
四.类的扩展
Category分类 、类别、类目
    使用分类扩展类,并且不修改类原来的代码
    1.分类只能增加方法,不能增加成员变量,添加成员变量可以使用继承。
    2.分类的方法实现中可以使用成员变量
    3.分类的优先级最高,先去分类中找,再去原来的类中找,最后到父类中去找
    4.分类可以重新实现原来类中的方法,但是会覆盖掉原来的方法,会有警告
    5.多个分类实现的方法,最后一个编译的有效

    //声明
    @interface 类名(分类名称)
    @end

    //实现
    @implementation 类名(分类名称)
    @end
    xcode添加分类->项目右键-NewFile OS X->Cocoa->Objective-C category(在Xcode6中已移除,如想使用需要手动添加模版文件)
    xcode6 想要添加分类需要 项目右键-NewFile OS X->Cocoa->Objective-C File 然后在弹出窗口中的 File Type:Category然后输入其它之后添加。

扩展
Extension
    作用:定义私有方法。可以隐藏不对外公布的方法。多用于隐藏一些中间步骤的方法。
    写法:在.m文件中 @implementation 前实现
    例如在 @implementation之前加上
    @interface ViewController ()
    {
        int a;//默认私有
    }
    @end

协议
protocol
    可以实现类似多继承的方法。一个类遵守多个协议<...,...>
    在协议里声明方法来让类遵守
     @required //默认是必须实现的
    - (void)method1;
    - (void)method2;
    @optional //可以选择实现



五.类的深入研究
    1.利用类需要先创建类类型对象
    2.类需要占据存储空间。
    3.每个类对象,占据不同的存储空间
    4.类本身也是一个对像,是Class类型的对象

Class类型的定义
    typedef struct objc_class *Class;
    类名就代表着类对象,每个类只有一个类对象

内存中的类对象
    Person * p = [[Person alloc] init];

获取内存中的类对象
    1.Class c = [p class];
    2.Class c2 = [Person class];

    NSLog(@"c=%p,c2=%p",c,c2);
    
    //类对象 == 类
    Class c = [p class];
    [c test];
    
    Person *p2 = [[c new] init];

类的加载
    1.当程序启动时,就会加载项目中所有的类和分类,而且加载后会调用每个类和分类的+load方法,只会调用一次.
    2.当第一次使用某个类时,就会调用当前类的+initialize方法,但是会先找分类的,因为有优先级
    3.加载优先级 顺序 先初始化父类-初始化子类
    4.initialize调用优先级 先最后编译的分类-本类-父类

    @implementation Person
    + (void)test
    {
        NSLog(@"test");
    }
    //当程序启动的时候,就会加载一次项目中所有的类。类加载完毕后就会调用+load方法,加载顺序是先父类后子类
    + (void)load
    {
        NSLog(@"load");
    }
    //当第一次使用这个类的时候,就会调用一次initialize方法
    //当分类和类都有initialize方法时,只会调用分类的initialize方法
    + (void)initialize
    {
        NSLog(@"initialize");
    }


NSLog函数的工作原理
    Person *p = [[Person alloc] init];
    //默认情况下,利用NSLog和%@输出对象时,结果是:<类名:内存地址>
    //1.首先调用对象的-description方法
    //2.拿到-description方法的返回值(NSString *)显示到屏幕上
    //3.-description方法默认返回的是"类名+内存地址"
    //子类会继承重写的方法
    NSLog(@"%@",p);


Class c = [Person class];
    //1.首先调用类的+description方法
    //2.拿到+description方法的返回值(NSString *)显示到屏幕上
    //3.+description方法默认返回的是"类名"
    NSLog(@"%@",c);
    重写-description方法

NSLog的其它功能
    __func__ %s  Current function signature.
    __LINE__ %d  Current line number in the source code file.
    __FILE__ %s Full path to the source code file.
    __PRETTY_FUNCTION__ %s Like__func__,but includes verbose type information in C++ code.s

SEL
    每个SEL对应一个方法地址
    每个类的方法列表都存储在类对象中
    根据一个SEL对象就可以找到方法的地址,进而调用方法
    SEL类型的定义
    typedef struct objc_selector *SEL

SEL对象的创建
    [p test:@"123"];
    SEL s = @selector(test:);
    NSString *name = @"test";
    SEL s2 = NSSelectorFromString(@"test");
    [p performSelector:s withObject:@"456"];

SEL对象的其他用法
    //将 SEL对象转为NSString对象
    NSString *str  =NSStringFromSelector(@selector(test));

    Person *p = [Person new]
    //调用对象p的test方法
    [p performSelector:@selector(test)];

_cmd
    //每个方法内部都有一个_cmd,_cmd代表当前方法
    用法
    NSString *str = NSStringFromSelector(_cmd);
    NSLog(@"调用了方法%@",str);
    //死循环

    [self performSelector:_cmd];


1.点语法
点语法的本质还是方法调用
比如 p.age=10; 就是转换为 [p setAge:10];
     int a = p.age 转换为 int a = [p age];

xcode - Create a new Xcode project - OS X- Application - Command Line Tool - create

添加类
OS X - Cocoa(Source) - Objective-C class -> Class:Person ->Subclass of :NSObject -> Language:Objective-C - Create
生成Person.h与.m

command+r 运行

xcode6 需要点 右下角的[ |]图标(Hide the Console)才能看到控制台


Person.h->

//
//  person.h
//  oc06核心语法
//
//  Created by Whome on 14-10-27.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Person : NSObject
{
    int _age;
    NSString * _name;
}

- (void) setAge:(int)age;
- (int) age;
- (void) setName:(NSString *)name;
- (NSString *) name;

@end



Person.m->
//
//  person.m
//  oc06核心语法
//
//  Created by Whome on 14-10-27.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import "Person.h"

@implementation Person

- (void) setAge:(int)age
{
    //self.age = 10; 是死循环
    _age = age;
    NSLog(@"setAge:%d",self->_age);
}
- (int) age
{
    NSLog(@"age:%d",self->_age);
    return self->_age;
}
- (void) setName:(NSString *)name
{
    _name = name;
    NSLog(@"setName:%@",self->_name);
}
- (NSString *) name
{
    NSLog(@"name:%@",self->_name);
    return self->_name;
}

@end



main.m->
//
//  main.m
//  oc06核心语法
//
//  Created by Whome on 14-10-27.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Person.h"
/*
 点语法的本质还是方法调用
 比如 p.age=10; 就是转换为 [p setAge:10];
 int a = p.age 转换为 int a = [p age];
 */

int main() {
    
    Person *p = [Person new];
    
    p.age = 10;
    int a = p.age;
    NSLog(@"a:%d",a);
    p.name = @"is name";
    NSString *s = p.name;
    
    NSLog(@"s:%@",s);
    
    return 0;
}



控制台输出
2014-10-27 06:42:57.278 oc06核心语法[502:303] setAge:10
2014-10-27 06:42:57.287 oc06核心语法[502:303] age:10
2014-10-27 06:42:57.288 oc06核心语法[502:303] a:10
2014-10-27 06:42:57.294 oc06核心语法[502:303] setName:is name
2014-10-27 06:42:57.302 oc06核心语法[502:303] name:is name
2014-10-27 06:42:57.303 oc06核心语法[502:303] s:is name
Program ended with exit code: 0

2.成员变量作用域
1.基本概念
局部变量、全局变量都有自己的作用域,成员变量也不例外
2.类型
>@private:只能在当前类的实现@implementation中直接访问
>@protected:可以在当前类以及子类的实现@implementation中直接访问
>@public:任何地方都可直接访问
>@package:同一个“体系内”(框架)可以访问,介于@private@public之间
3.继承补充
>专业术语 父类\超类 superclass 子类 subclass\subclasses 单继承
4.@implementation补充
没有@interface,只有@implementaton,也可以开发一个类,在.m文件进行声明
在声明里写的成员变量,默认是private
实现里面也能写成员变量 默认是私有,因为不会被其他文件包含,无法改设置就算写上@public也没用
(@interface)声明和(@implementation)实现里面不能定义同名的变量

添加类
OS X - Cocoa(Source) - Objective-C class -> Class:Person ->Subclass of :NSObject -> Language:Objective-C - Create
生成Person.h与.m

Person.h->
//
//  Person.h
//  02成员变量的作用域
//
//  Created by Whome on 14-10-28.
//  Copyright (c) 2014年 Whome. All rights reserved.
//


#import <Foundation/Foundation.h>

@interface Person : NSObject
{
    int _no;
    
    @public //在作何地方都能直接方问对象的成员变量
    int _age;
    
    @private//只能在当前类的对象方法中直接访问
    int _height;
    
    @protected //可以在当前类及其子类的对象方法中直接访问
    int _weight;
}
- (void)setHeight:(int) height;
- (int)height;
- (void)test;
@end



Person.m->
//
//  Person.m
//  02成员变量的作用域
//
//  Created by Whome on 14-10-28.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import "Person.h"

@implementation Person
{
    int _aaa;//默认就是私有
    
    @public
    int _bbb;
    
}
- (void)test
{
    _age = 19;
    _height = 20;
    _weight = 50;
    _aaa = 10;
}
- (void)setHeight:(int)height{
    _height = height;
}
- (int)height
{
    return _height;
}
@end

Student.h->
//
//  Student.h
//  02成员变量的作用域
//
//  Created by Whome on 14-10-28.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import "Person.h"

@interface Student : Person
- (void)study;
@end

Student.m->
//
//  Student.m
//  02成员变量的作用域
//
//  Created by Whome on 14-10-28.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import "Student.h"

@implementation Student
- (void)study
{
    //_height = 10;
    [self setHeight:10];
    
    int h = [self height];
    
    _weight = 100;
    
    NSLog(@"h:%d",h);
}
@end

Car.m->

//
//  <pre name="code" class="objc">Car .m
//  02成员变量的作用域
//
//  Created by Whome on 14-10-28.
//  Copyright (c) 2014年 Whome. All rights reserved.
//
#import "Person.h"
#import "Student.h"
@implementation Car : NSObject
{
    @public
    int _speed;
}
- (void)setSpeed:(int)speed
{
    _speed = speed;
}
- (int)speed
{
    return _speed;
}
- (void) test{
    NSLog(@"speed:%d",_speed);
}
@end

 



main.m->
#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Student *stu = [Student new];
        
        [stu setHeight:10];
        
        NSLog(@"%d",[stu height]);
        
        Car *c = [Car new];
        c->_speed = 250;
        c.speed = 10;
        
        NSLog(@"speed:%d",c.speed);
        
        Person *p = [Person new];
        //私有的private
      //  p->_bbb = 10;
        p->_age = 100;
        //私有的private
     //   p->_height = 20;
        
    }
    return 0;
}

控制台:
2014-10-28 07:55:13.150 02成员变量的作用域[630:303] 10
2014-10-28 07:55:13.153 02成员变量的作用域[630:303] speed:10
Program ended with exit code: 0


1.@property
在@interface和@end之间
编译器特性,当遇到@property int age自动生成某个成员变量的setter和getter声明,不能重复声明
如果使用了@property,但是没有成员变量,则自动生成private类型的成员变量
缺点,成员变量是死的,无法设置public或protected


2.@synthesize
在@implementation和@end之间
自动生用age的setter和getter的实现,并且会访问_age这个成员变量
@synthesize age = _age;也可以@synthesize age = _age,name = _name;
如果@synthesize age没有指定,那么默认访问和age一样的成员变量

@property新特性
自从Xcode4.4以后,@property就独揽了@synthesize的功能,也不是说,@property可以同时声明成员变量的声明和实现

@property(nonatomic,retain) UIWindow *window;  

其中参数主要分为三类:

读写属性: (readwrite/readonly)
setter语意:(assign/retain/copy)
原子性: (atomicity/nonatomic)

 

各参数意义如下:

readwrite: 产生setter\getter方法
readonly: 只产生简单的getter,没有setter。
assign: 默认类型,setter方法直接赋值,而不进行retain操作
retain: setter方法对参数进行release旧值,再retain新值。
copy: setter方法进行Copy操作,与retain一样,不对旧值release
nonatomic: 禁止多线程,变量保护,提高性能

3.id
id是一种类似如 id d 所以变量名不能叫id,id是关键字
id是万能指针,能指向\操作任何OC对象
//id == NSObject *
typedef struct objc_object{
    Class isa;
}*id;
//id后面不加*
用id调用不存在的方法会报错

Person.h->

//
//  Person.h
//  03关键字
//
//  Created by Whome on 14-10-28.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Person : NSObject
{
   
    int _age;
     @private
    int _width;
}
//自动生成getter和setter及private类型的成员变量
@property int height;
@property NSString* name;
//自动生成getter和setter
@property int age;

- (void)setWidth:(int)width;
- (int)width;

@end




Person.m->

//
//  Person.m
//  03关键字
//
//  Created by Whome on 14-10-28.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import "Person.h"

@implementation Person

//自动实现setter和getter
@synthesize height = _height;

//没有@property int width会报错
//@synthesize width = _widht;

- (void)setWidth:(int)width{
    _width = width;
}

- (int)width{
    return _width;
}

@end



Student.h->
//
//  Student.h
//  03关键字
//
//  Created by Whome on 14-10-28.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import "Person.h"

@interface Student : Person

@end



Student.m->

//
//  Student.m
//  03关键字
//
//  Created by Whome on 14-10-28.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import "Student.h"

@implementation Student

@end



main.m->

//
//  main.m
//  03关键字
//
//  Created by Whome on 14-10-28.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Student.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        Person *p = [Person new];
        
        //只手动声明了成员变量
        p.age = 10;
        //纯@property
        p.height=10;
        //纯@property
        p.name = @"is name";
        //纯手动
        p.width = 10;
        
        NSLog(@"p.age:%d",p.age);
        NSLog(@"p.height:%d",p.height);
        NSLog(@"p.name:%@",p.name);
        NSLog(@"p.width:%d",p.width);
        
        Student *s = [Student new];
        
        
        //父类的成员变量是私有的无法->调用,但是setter/getter可以用
        //只手动声明了成员变量
        s.age = 10;
        //纯@property
        s.height=10;
        //纯@property
        s.name = @"is name";
        //纯手动
        s.width = 10;
        
        
        NSLog(@"s.age:%d",s.age);
        NSLog(@"s.height:%d",s.height);
        NSLog(@"s.name:%@",s.name);
        NSLog(@"s.width:%d",s.width);

        
        //id是一种类似如 id d 所以变量名不能叫id,id是关键字
        //id是万能指针,能指向\操作任何OC对象
        
        id d = [Student new];
        //无法直接用.语法来调用
        //d.age = 10;
        [d setAge:10];
        NSLog(@"d.age:%d",[d age]);
        
    }
    return 0;
}

控制台输出:
2014-10-29 00:10:15.692 03关键字[690:303] Hello, World!
2014-10-29 00:10:15.695 03关键字[690:303] p.age:10
2014-10-29 00:10:15.696 03关键字[690:303] p.height:10
2014-10-29 00:10:15.697 03关键字[690:303] p.name:is name
2014-10-29 00:10:15.698 03关键字[690:303] p.width:10
2014-10-29 00:10:15.699 03关键字[690:303] s.age:10
2014-10-29 00:10:15.700 03关键字[690:303] s.height:10
2014-10-29 00:10:15.701 03关键字[690:303] s.name:is name
2014-10-29 00:10:15.706 03关键字[690:303] s.width:10
2014-10-29 00:10:15.706 03关键字[690:303] d.age:10


1.new的用处
 完整地创建一个可用的对象
 1.分配存储空间 +alloc
 2.初始化 -init
 3.释放 -dealloc
Person *p3 = [[Person alloc] init];
 
//构造方法:是用来初始化对象的方法,是对象方法 -开头
//重写构造方法的目的:为了让对象创建出来,成员变量就会有一些固定的值
重写构造方法注意点
1.先调用父类的构造方法([super init])
2.再进行子类内部成员变量的初始化

//重写-init方法 - (id)init
//1.一定要调用回super的init方法:初始化父类中声明的一些成员变量和其他属性 self = [super init];//当前对象 self = [父类将isa初始化为当前类]

init的执行过程,运行原理
//子类实例被创建的时候会先创建父类实例(调用父类的无参数构造方法),然后再创建子类实例


 自定义构造函数规范
 1.一定是对象方法,一定以 - 开头
 2.返回值一般以id类型
 3.方法名一般以initWith开头



Person.h->

//
//  Person.h
//  04构造方法
//
//  Created by Whome on 14-10-29.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Person : NSObject
{
   // int _age;
   // NSString* _name;
}
@property int age;
@property NSString* name;
- (id)init;
/*
 自定义构造函数规范
 1.一定是对象方法,一定以 - 开头
 2.返回值一般以id类型
 3.方法名一般以initWith开头
 */
- (id)initWithName:(NSString *) name andAge:(int) age;
@end



Person.m->
//
//  Person.m
//  04构造方法
//
//  Created by Whome on 14-10-29.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import "Person.h"

@implementation Person
//重写重构方法
- (id)init
{
    //当前对象指针指向父类构造出来的对象
    //当前对象指针 self = [父类将isa初始化为当前类]
    self = [super init];
    
    //如果self不为0
    if(self){
        //初始化成员变量
        _age = 10;
    }
    return self;
}
- (id)initWithName:(NSString *)name andAge:(int)age
{
    if(self = [super init])
    {
        _name = name;
        _age = age;
    }
    return self;
}
@end



Student.h->

//
//  Student.h
//  04构造方法
//
//  Created by Whome on 14-10-29.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import "Person.h"

@interface Student : Person
{
    int _no;
}
@property int no;
- (id)init;
- (id)initWithName:(NSString *) name andAge:(int) age andNo:(int) no;
@end



Student.m->

//
//  Student.m
//  04构造方法
//
//  Created by Whome on 14-10-29.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import "Student.h"

@implementation Student
//重写重构方法
- (id)init
{
    //当前对象指针指向父类构造出来的对象
    //当前对象指针 self = [父类将isa初始化为当前类]
    //一定要调用父类的init方法,初始化一些父类声明的成员变量和方法
    self = [super init];
    
    //如果self不为0,如果对象初始化成功,能有必要进行接下来的初始化
    if(self){
        //初始化成员变量
        _no = 50;
    }
    //返回一个已初始化完毕的对象
    return self;
}
- (id)initWithName:(NSString *)name andAge:(int)age andNo:(int)no
{
    
    if(self = [super initWithName:name andAge:age ])
    {
        //如果_name是子类可继随的那么
        //_name = name;
        //如果_name是私有的那么
        //self.name = name;
        //如果想在父类构造时就初始化,而且并不关心父类的成员变量那么
        //[super initWithName:name andAge:age ]
        
        _no = no;
    }
    return self;
}

@end



main.m->

//
//  main.m
//  04构造方法
//
//  Created by Whome on 14-10-29.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Student.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        /*
        1.new的用处
        完整地创建一个可用的对象
        1.分配存储空间 +alloc
        2.初始化 -init
        */
        Student *s = [[Student alloc] init];
        NSLog(@"age:%d,no:%d",s.age,s.no);
        
        /*
         重写构造方法的执行顺序
         student init super init
         person init super init
         nsobject init ....被封闭了
         返回一个class
         */
        /*
         自定义构造函数规范
         1.一定是对象方法,一定以 - 开头
         2.返回值一般以id类型
         3.方法名一般以initWith开头
         */
         s = [[Student alloc] initWithName:@"is name" andAge:10 andNo: 20];
         NSLog(@"age:%d,no:%d,name:%@",s.age,s.no,s.name);
    }
    return 0;
}

控制台->

2014-10-30 06:24:35.326 04构造方法[398:303] Hello, World!
2014-10-30 06:24:35.332 04构造方法[398:303] age:10,no:50
2014-10-30 06:24:35.336 04构造方法[398:303] age:10,no:20,name:is name


Category分类 、类别、类目
/*使用分类扩展类,并且不修改类原来的代码
1.分类只能增加方法,不能增加成员变量,添加成员变量可以使用继承。
2.分类的方法实现中可以使用成员变量
3.分类的优先级最高,先去分类中找,再去原来的类中找,最后到父类中去找
4.分类可以重新实现原来类中的方法,但是会覆盖掉原来的方法,会有警告
5.多个分类实现的方法,最后一个编译的有效
*/
//声明
@interface 类名(分类名称)
@end

//实现
@implementation 类名(分类名称)
@end


xcode添加分类->项目右键-NewFile OS X->Cocoa->Objective-C category(在Xcode6中已移除,如想使用需要手动添加模版文件)
xcode6 想要添加分类需要 项目右键-NewFile OS X->Cocoa->Objective-C File 然后在弹出窗口中的 File Type:Category然后输入其它之后添加。

扩展
Extension
作用:定义私有方法。可以隐藏不对外公布的方法。多用于隐藏一些中间步骤的方法。
写法:在.m文件中 @implementation 前实现
例如在 @implementation之前加上
@interface ViewController ()
{
    int a;//默认私有
}
@end

协议
protocol
可以实现类似多继承的方法。一个类遵守多个协议<...,...>
在协议里声明方法来让类遵守
 @required //默认是必须实现的
- (void)method1;
- (void)method2;
@optional //可以选择实现

给系统自带类添加分类
1.给NSString增加一个类方法:计算某个字符串中阿拉伯数字的个数
2.给NSString增加一个对象方法:计算当前字符串中阿拉伯数字的个数


Person.h->

#import <Foundation/Foundation.h>

@interface Person : NSObject
{
    //@private
    //int _age;
}
@property int age;
- (void)test;
@end

Person.m->
#import "Person.h"

@implementation Person
- (void)test
{
    NSLog(@"person");
}
@end

Person+sum.h->
#import "Person.h"

@interface Person (sum)
- (int)sumWithAge:(int)age1 andAge2:(int)age2;
- (void)test;
@end

Person+sum.m->
#import "Person+sum.h"

@implementation Person (sum)
- (int)sumWithAge:(int)age1 andAge2:(int)age2
{
    self.age = age2+age2;
    NSLog(@"self.age:%d",self.age);
    //出错,因为没有在类声明变量。
    //_age = 0;
    //age = 0;
    //self->_age=0;
    //self->age =0;
    /*
    self->age =age+age2;
    return self->_age;
     */
    return self.age;
}
- (void)test
{
    NSLog(@"person+sum");
}
@end

NSString+count.h->
#import <Foundation/Foundation.h>


/*
 给系统自带类添加分类
 1.给NSString增加一个类方法:计算某个字符串中阿拉伯数字的个数
 2.给NSString增加一个对象方法:计算当前字符串中阿拉伯数字的个数
 */
@interface NSString (count)
+ (int) numberCountOfString:(NSString *)str;
- (int)numberCount;
@end

NSString+count.m->
#import "NSString+count.h"

@implementation NSString (count)
// 计算某个字符串中阿拉伯数字的个数
+ (int) numberCountOfString:(NSString *)str
{
    int count=0;
    //获取长度并循环
    for(int i=0;i<str.length;i++)
    {
        //获取字符
        unichar c = [str characterAtIndex:i];
        //将数字挑选出来
        if(c>'0' && c<'9')
        {
            count++;
            NSLog(@"%c",c);
        }
    }
    return count;
}
//计算当前字符串中阿拉伯数字的个数
- (int)numberCount
{
    int count=0;
    for(int i=0;i<self.length;i++)
    {
        unichar c = [self characterAtIndex:i];
        if(c>'0' && c<'9')
        {
            count++;
            NSLog(@"%c",c);
        }
    }
    return count;
}
@end

main.m->
#import <Foundation/Foundation.h>

#import "Person.h"
#import "Person+sum.h"
#import "NSString+count.h"

/*
 Category分类 、类别、类目
 使用分类扩展类,并且不修改类原来的代码
 1.分类只能增加方法,不能增加成员变量,添加成员变量可以使用继承。
 2.分类的方法实现中可以使用成员变量
 3.分类的优先级最高,先去分类中找,再去原来的类中找,最后到父类中去找
 4.分类可以重新实现原来类中的方法,但是会覆盖掉原来的方法,会有警告
 5.多个分类实现的方法,最后一个编译的有效
 */
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        Person *p = [[Person alloc]init];
        
        int age = [p sumWithAge:10 andAge2:20];
        NSLog(@"age:%d",age);
        
        [p test];
        
       
        
        int count = [NSString numberCountOfString:@"a12d5x778" ];
        NSLog(@"count:%d",count);

        NSString *s = @"ab234x278";
        count = [s numberCount];
        NSLog(@"count:%d",count);

        count = [@"asdf2ssdf2" numberCount];
        NSLog(@"count:%d",count);


    }
    
    return 0;
}


控制台:
2014-11-09 19:43:05.706 05类的分类[852:303] Hello, World!
2014-11-09 19:43:05.709 05类的分类[852:303] self.age:40
2014-11-09 19:43:05.710 05类的分类[852:303] age:40
2014-11-09 19:43:05.710 05类的分类[852:303] person+sum
2014-11-09 19:43:05.711 05类的分类[852:303] 1
2014-11-09 19:43:05.711 05类的分类[852:303] 2
2014-11-09 19:43:05.712 05类的分类[852:303] 5
2014-11-09 19:43:05.712 05类的分类[852:303] 7
2014-11-09 19:43:05.714 05类的分类[852:303] 7
2014-11-09 19:43:05.714 05类的分类[852:303] 8
2014-11-09 19:43:05.715 05类的分类[852:303] count:6
2014-11-09 19:43:05.717 05类的分类[852:303] 2
2014-11-09 19:43:05.718 05类的分类[852:303] 3
2014-11-09 19:43:05.719 05类的分类[852:303] 4
2014-11-09 19:43:05.719 05类的分类[852:303] 2
2014-11-09 19:43:05.720 05类的分类[852:303] 7
2014-11-09 19:43:05.721 05类的分类[852:303] 8
2014-11-09 19:43:05.721 05类的分类[852:303] count:6
2014-11-09 19:43:05.722 05类的分类[852:303] 2
2014-11-09 19:43:05.723 05类的分类[852:303] 2
2014-11-09 19:43:05.727 05类的分类[852:303] count:2

可能性
我觉得跟权限没关系应该是分类在调用这个变量的时候property还没有生成
那么就只有一个原因,  分类可以重写setAge和(get)age方法.
又因为set get 这两个方法一旦重写 那property 就不在会生成_age变量;

所以OC为了避免这种情况  直接限制在有分类的情况 必须自己书写变量 不能用property 这样就不会导致重写set get会让property失效了
你可以在正常情况下 写了property  然后在重写set get方法  你会发现找不到变量


类的深入研究
1.利用类需要先创建类类型对象
2.类需要占据存储空间。
3.每个类对象,占据不同的存储空间
4.类本身也是一个对像,是Class类型的对象

Class类型的定义
typedef struct objc_class *Class;
类名就代表着类对象,每个类只有一个类对象

内存中的类对象
Person * p = [[Person alloc] init];

获取内存中的类对象
1.Class c = [p class];
2.Class c2 = [Person class];

NSLog(@"c=%p,c2=%p",c,c2);

//类对象 == 类
Class c = [p class];
[c test];

Person *p2 = [[c new] init];

类的加载
1.当程序启动时,就会加载项目中所有的类和分类,而且加载后会调用每个类和分类的+load方法,只会调用一次.
2.当第一次使用某个类时,就会调用当前类的+initialize方法,但是会先找分类的,因为有优先级
3.加载优先级 顺序 先初始化父类-初始化子类
4.initialize调用优先级 先最后编译的分类-本类-父类

@implementation Person
+ (void)test
{
    NSLog(@"test");
}
//当程序启动的时候,就会加载一次项目中所有的类。类加载完毕后就会调用+load方法,加载顺序是先父类后子类
+ (void)load
{
    NSLog(@"load");
}
//当第一次使用这个类的时候,就会调用一次initialize方法
//当分类和类都有initialize方法时,只会调用分类的initialize方法
+ (void)initialize
{
    NSLog(@"initialize");
}


NSLog函数的工作原理
Person *p = [[Person alloc] init];
//默认情况下,利用NSLog和%@输出对象时,结果是:<类名:内存地址>
//1.首先调用对象的-description方法
//2.拿到-description方法的返回值(NSString *)显示到屏幕上
//3.-description方法默认返回的是"类名+内存地址"
//子类会继承重写的方法
NSLog(@"%@",p);


Class c = [Person class];
//1.首先调用类的+description方法
//2.拿到+description方法的返回值(NSString *)显示到屏幕上
//3.+description方法默认返回的是"类名"
NSLog(@"%@",c);
重写-description方法

NSLog的其它功能
__func__ %s  Current function signature.
__LINE__ %d  Current line number in the source code file.
__FILE__ %s Full path to the source code file.
__PRETTY_FUNCTION__ %s Like__func__,but includes verbose type information in C++ code.s

SEL
每个SEL对应一个方法地址
每个类的方法列表都存储在类对象中
根据一个SEL对象就可以找到方法的地址,进而调用方法
SEL类型的定义
typedef struct objc_selector *SEL

SEL对象的创建
[p test:@"123"];
SEL s = @selector(test:);
NSString *name = @"test";
SEL s2 = NSSelectorFromString(@"test");
[p performSelector:s withObject:@"456"];

SEL对象的其他用法
//将 SEL对象转为NSString对象
NSString *str  =NSStringFromSelector(@selector(test));

Person *p = [Person new]
//调用对象p的test方法
[p performSelector:@selector(test)];

_cmd
//每个方法内部都有一个_cmd,_cmd代表当前方法
用法
NSString *str = NSStringFromSelector(_cmd);
NSLog(@"调用了方法%@",str);
//死循环
[self performSelector:_cmd];


main.m->

//
//  main.m
//  06类的深入
//
//  Created by Whome on 14-11-7.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Person.h"


int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        
        /*
         Class类型的定义
         typedef struct objc_class *Class;
         类名就代表着类对象,每个类只有一个类对象
         */
        
        //获取内存中的类对象
        Person *p = [[Person alloc]init];
        Class c = [p class];
        Class c1 = [Person class];
        
        NSLog(@"c=%p,c1=%p",c,c1);
        
        //类对象 == 类
        Class c2 = [p class];
        [c test];
        
        Person *p1 = [[c2 new] init];
        [p1 test];
        
        /*
         类的加载
         1.当程序启动时,就会加载项目中所有的类和分类,而且加载后会调用每个类和分类的+load方法,只会调用一次.
         2.当第一次使用某个类时,就会调用当前类的+initialize方法,但是会先找分类的,因为有优先级
         3.加载优先级 顺序 先初始化父类-初始化子类
         4.initialize调用优先级 先最后编译的分类-本类-父类
         */
        
        
        /*
         %@ 对象
         %d, %i 整数
         %u,%z 无符整形
         %f 浮点/双字
         %x, %X 十六进制整数
         %o 八进制整数
         %zu size_t
         %p 指针
         %e 浮点/双字 (科学计算)
         %g 浮点/双字
         %s C字符串
         %.*s Pascal字符串
         %c 字符
         %C unichar
         %lld 64位长整数(long long)
         %llu 无符64位长整数
         %Lf 64位双字
         %hhd    BOOL布尔类型
         __func__ %s  Current function signature.
         __LINE__ %d  Current line number in the source code file.
         __FILE__ %s Full path to the source code file.
         __PRETTY_FUNCTION__ %s Like__func__,but includes verbose type information in C++ code.s
         */
        NSLog(@"__func__:%s",__func__);
        NSLog(@"__LINE__:%d",__LINE__);
        NSLog(@"__FILE__:%s",__FILE__);
        NSLog(@"__PRETTY_FUNCTION__:%s",__PRETTY_FUNCTION__);
       // NSLog函数的工作原理
        Student *p2 = [[Student alloc] init];
        //默认情况下,利用NSLog和%@输出对象时,结果是:<类名:内存地址>
        //1.首先调用对象的-description方法
        //2.拿到-description方法的返回值(NSString *)显示到屏幕上
        //3.-description方法默认返回的是"类名+内存地址"
        NSLog(@"p2:%@",p2);
        
        
        Class c3 = [Student class];
        //1.首先调用类的+description方法
        //2.拿到+description方法的返回值(NSString *)显示到屏幕上
        //3.+description方法默认返回的是"类名"
        NSLog(@"c3:%@",c3);
        //重写-description方法

        /*
        SEL
        每个SEL对应一个方法地址
        每个类的方法列表都存储在类对象中
        根据一个SEL对象就可以找到方法的地址,进而调用方法
        SEL类型的定义
        typedef struct objc_selector *SEL
        */
        //SEL对象的创建
        [p testStr:@"123"];
        SEL s = @selector(testStr:);
        NSString *name = @"testStr:";
        //SEL s2 = NSSelectorFromString(@"testStr");
        SEL s2 = NSSelectorFromString(name);
        
        [p performSelector:s withObject:@"456"];
        [p performSelector:s2 withObject:@"56"];
        
        
        //SEL对象的其他用法
        //将 SEL对象转为NSString对象
        NSString *str  =NSStringFromSelector(@selector(test));
        
        NSLog(@"str%@:",str);
        
        //间接调用对象p的test方法
        s = @selector(test);
        [p performSelector:s];
        //不知道为什么调用test报错
    /*
    保留test对象方法在编辑时报Multiple methods named 'test' found with mismatched result,parameter type or attributes
    只保类test类方法在编译时报*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Person test]: unrecognized selector sent to instance 0x100104fd0'
    */
        [p performSelector:@selector(test2)];
       
    }
    return 0;
}



Person.h->
//
//  Person.h
//  06类的深入
//
//  Created by Whome on 14-11-7.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Person : NSObject
+ (void)test;
- (void)test;
- (void)test2;
- (void)testStr:(NSString*)str;
@end



Person.m->
//
//  Person.m
//  06类的深入
//
//  Created by Whome on 14-11-7.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import "Person.h"

@implementation Person
+ (void)test
{
    NSLog(@"Person test");
}
- (void)test
{
    NSLog(@"Person -test");
    /*
     _cmd
     每个方法内部都有一个_cmd,_cmd代表当前方法
     用法
     */
    NSString *str = NSStringFromSelector(_cmd);
    NSLog(@"调用了方法%@",str);
    //死循环
    //[self performSelector:_cmd];
}
//当程序启动的时候,就会加载一次项目中所有的类。类加载完毕后就会调用+load方法,加载顺序是先父类后子类
+ (void)load
{
    NSLog(@"Person load");
}
//当第一次使用这个类的时候,就会调用一次initialize方法
//当分类和类都有initialize方法时,只会调用分类的initialize方法
+ (void)initialize
{
    NSLog(@"Person initialize");
}
//默认情况下,利用NSLog和%@输出对象时,结果是:<类名:内存地址>
//1.首先调用对象的-description方法
//2.拿到-description方法的返回值(NSString *)显示到屏幕上
//3.-description方法默认返回的是"类名+内存地址"
//子类会继承这个方法
- (NSString*)description
{
    return @"NSLog description 返回值";
}
- (void)testStr:(NSString*)str{
    NSLog(@"%@",str);
}
- (void)test2{
    NSLog(@"- test2");
    NSString *str = NSStringFromSelector(_cmd);
    NSLog(@"调用了方法%@",str);
}
+ (void)test2{
    NSLog(@"+ test2");
}
@end

Person+Mj.h->
#import "Person.h"

@interface Person (MJ)

@end

Person+Mj.m->
#import "Person+MJ.h"

@implementation Person (MJ)
//当程序启动的时候,就会加载一次项目中所有的类。类加载完毕后就会调用+load方法,加载顺序是先父类后子类
+ (void)load
{
    NSLog(@"Person+MJ load");
}
//当第一次使用这个类的时候,就会调用一次initialize方法
//当分类和类都有initialize方法时,只会调用分类的initialize方法
+ (void)initialize
{
    NSLog(@"Person+MJ initialize");
}
@end


Student.h->
#import "Person.h"

@interface Student : Person
+ (void)test;
@end


Student.m->

#import "Student.h"

@implementation Student
+ (void)test
{
    NSLog(@"Student test");
}
//当程序启动的时候,就会加载一次项目中所有的类。类加载完毕后就会调用+load方法,加载顺序是先父类后子类
+ (void)load
{
    NSLog(@"Student load");
}
//当第一次使用这个类的时候,就会调用一次initialize方法
//当分类和类都有initialize方法时,只会调用分类的initialize方法
+ (void)initialize
{
    NSLog(@"Student initialize");
}
@end



控制台

2014-11-09 07:41:25.908 06类的深入[894:303] Person load
2014-11-09 07:41:25.911 06类的深入[894:303] Student load
2014-11-09 07:41:25.912 06类的深入[894:303] Person+MJ load
2014-11-09 07:41:25.913 06类的深入[894:303] Hello, World!
2014-11-09 07:41:25.913 06类的深入[894:303] Person+MJ initialize
2014-11-09 07:41:25.914 06类的深入[894:303] c=0x1000026d0,c1=0x1000026d0
2014-11-09 07:41:25.915 06类的深入[894:303] Person test
2014-11-09 07:41:25.916 06类的深入[894:303] - test2
2014-11-09 07:41:25.916 06类的深入[894:303] 调用了方法test2
2014-11-09 07:41:25.919 06类的深入[894:303] __func__:main
2014-11-09 07:41:25.919 06类的深入[894:303] __LINE__:73
2014-11-09 07:41:25.921 06类的深入[894:303] __FILE__:
2014-11-09 07:41:25.921 06类的深入[894:303] __PRETTY_FUNCTION__:int main(int, const char **)
2014-11-09 07:41:25.922 06类的深入[894:303] Student initialize
2014-11-09 07:41:25.923 06类的深入[894:303] p2:NSLog description 返回值
2014-11-09 07:41:25.924 06类的深入[894:303] c3:Student
2014-11-09 07:41:25.925 06类的深入[894:303] 123
2014-11-09 07:41:25.925 06类的深入[894:303] strtest:
Program ended with exit code: 0

------ Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值