【iOS 开发】Objective - C 面向对象 - 方法 | 成员变量 | 隐藏封装 | KVC | KVO | 初始化 | 多态(一)

本文涉及的产品
访问控制,不限时长
简介: 【iOS 开发】Objective - C 面向对象 - 方法 | 成员变量 | 隐藏封装 | KVC | KVO | 初始化 | 多态(一)

一. Objective-C 方法详解



1. 方法属性



(1) OC 方法传参机制



Object-C 方法传参机制 : OC 中得参数传递都是值传递, 传入参数的是参数的副本;


-- 基本类型 (值传递) : int 等基本类型直接传入 这些基本类型的的副本;


-- 指针类型 (地址传递) : 使用指针变量作为参数, 传递的也是指针变量的副本, 但是这个副本本身的值是一个地址, 地址 变量 和 地址 变量的副本 还是指向同一个地址;







(2) OC 方法 与 传统函数



方法 与 传统函数 :


-- 结构化编程语言 : 整个软件由一个函数构成, 如 C 语言, 一个 main 函数就是整个软件架构;


-- 面向对象语言 : 整个软件由 类 组成, 软件中的 方法 必须属于类, 不能独立存在;







(3) 类方法 与 实例方法



方法定义 : 方法只能定义在类中, 不能独立定义;


-- 类方法 : 使用 "+" 标识, 这个方法属于类方法, 使用 [类 方法] 调用;


-- 实例方法 : 使用 "-" 标识, 该方法属于实例方法, 使用 [对象 方法] 调用;







(4) 方法属性



方法属性 :


-- 不独立存在 : 不能独立定义, 只能在类中定义;


-- 类 对象 : 方法要么属于类, 要么属于对象;


-- 方法执行 : 方法不能独立执行, 需要使用 类 或 对象作为调用者;







2. 形参个数可变的方法




形参可变方法简介 :


-- 方法定义 : 最后一个形参后增加 逗号 和 三点 ", ..." ;


-- 示例 : NSLog() 函数可以传入任意多参数, 该函数就是形参个数可变的方法;




示例代码 :


-- 接口 :



/*************************************************************************
    > File Name: Varargs.h
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 日  9/27 22:04:34 2015
 ************************************************************************/
#import <Foundation/Foundation.h>
@interface Varargs : NSObject
/*
 * 形参个数可变方法
 * 在 NSString * 类型参数后面加上 ",..." 一个逗号 三个点号, 
 * 表明该方法还可以接受 n 个 NSString * 类型的参数
 */
-(void) varargs_test : (NSString *) str, ...;
@end

-- 实现 :



/*************************************************************************
    > File Name: Varargs.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 日  9/27 22:24:55 2015
 ************************************************************************/
#import "Varargs.h"
@implementation Varargs
-(void) varargs_test : (NSString *) str, ...
{
  /*
  * va_list 类型 : 用于指向可变参数列表的指针变量
  */
  va_list argList;
  // str 如果为 null 的话, 地址就会为0
  if(str)
  {
  NSLog(@"%@", str);
  /*
   * 开始处理可变形参的列表, 
   * 并让指针变量指向可变形参列表的第一个参数
   * 开始提取可变参数列表的参数
   */
  va_start(argList, str);
  /*
   * va_arg : 提取指针当前指向的参数, 
   * 并将指针移动到下一个参数
   */
  NSString * arg = va_arg(argList, id);
  //如果指针指向的参数 不为 nil , 则进入循环体
  while(arg)
  {
    NSLog(@"%@", arg);
    arg = va_arg(argList, id);
  }
  /*
   * var_end : 结束处理可变形参, 释放指针变量
   */
  va_end(argList);
  }
}
@end



-- main 函数 :



/*************************************************************************
    > File Name: VarargsTest.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 日  9/27 22:33:09 2015
 ************************************************************************/
#import "Varargs.h"
int main(int argc, char * argv[])
{
  @autoreleasepool {
  Varargs * va = [[Varargs alloc]init];
  [va varargs_test : @"参数一", @"参数二", @"参数三", @"参数四", nil];
  }
}


-- 执行过程 : 执行  clang -fobjc-arc -framework Foundation Varargs.m VarargsTest.m 命令;


octopus-2:oc_object octopus$ clang -fobjc-arc -framework Foundation Varargs.m VarargsTest.m 
octopus-2:oc_object octopus$ ./a.out 
2015-09-30 08:58:55.177 a.out[2823:507] 参数一
2015-09-30 08:58:55.180 a.out[2823:507] 参数二
2015-09-30 08:58:55.180 a.out[2823:507] 参数三
2015-09-30 08:58:55.181 a.out[2823:507] 参数四
octopus-2:oc_object octopus$




二. Object-C 成员变量







1. 成员变量机制



(1) 变量分类



变量分类 : 成员变量, 局部变量, 全局变量;


-- 局部变量 : 在函数里面定义的变量;


-- 全局变量 : 在函数外定义的变量;


-- 成员变量 : 在下面讲解;





(2) 成员变量简介



成员变量 : 在类 接口 或  实现 部分定义的变量, 都是实例变量, 不支持真正的类变量;


-- 实例变量 : 类对象被创建开始存在, 系统销毁对象, 实例变量就会随之销毁;


-- 实例变量访问 : "实例->实例变量";





(3) 成员变量 源码示例



示例源码 :



/*************************************************************************
    > File Name: OCPerson.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 三  9/30 09:10:09 2015
 ************************************************************************/
#import <Foundation/Foundation.h>
@interface OCPerson : NSObject
{
  //定义实例变量
  @public
  NSString * _name;
  int _age;
}
@end
@implementation OCPerson
@end
int main(int argc, char * argv[])
{
  @autoreleasepool {
  //创建成员变量
  OCPerson *p =[[OCPerson alloc] init];
  //通过指针变量访问两个实例变量
  NSLog(@"p->_name : %@ , p->_age : %d", p->_name, p->_age);
  //通过指针访问变量为两个成员变量赋值
  p->_name = @"Jim";
  p->_age = 18;
  NSLog(@"p->_name : %@ , p->_age : %d", p->_name, p->_age);
  OCPerson *p1 = [[OCPerson alloc] init];
  OCPerson *p2 = [[OCPerson alloc] init];
  p1->_name = @"Tom";
  p2->_name = @"Keen";
  NSLog(@"p1->_name : %@ , p2->_name : %@", p1->_name, p2->_name);
  }
}


-- 执行结果 :


octopus-2:oc_object octopus$ clang -fobjc-arc -framework Foundation OCPerson.m 
octopus-2:oc_object octopus$ ./a.out 
2015-09-30 09:17:38.510 a.out[2858:507] p->_name : (null) , p->_age : 0
2015-09-30 09:17:38.513 a.out[2858:507] p->_name : Jim , p->_age : 18
2015-09-30 09:17:38.513 a.out[2858:507] p1->_name : Tom , p2->_name : Keen
octopus-2:oc_object octopus$




(4) 成员变量 源码示例解析



示例解析 :


-- 成员变量初始化 : 创建对象时系统会为为成员变量赋初始值, 基础类型 0, 指针类型 nil;


-- 初始化过程 : 执行 "OCPerson *p1 = [[OCPerson alloc] init]" 语句时 系统为 OCPerson 对象的成员变量分配内存空间, 并初始化, 并将对象赋给 p1 变量;







2. 模拟类变量




前提 : Object-C 不支持 类变量, 但是可以使用 全局变量来模拟类变量;




static 关键字 : 不能修饰成员变量, 只能修饰 局部变量 和 全局变量;


-- 修饰局部变量 : 将局部变量存储到静态存储区;


-- 修饰全局变量 : 限制全局变量只能在当前文件中访问;


-- 修饰函数 : 限制该函数只能在当前源文件中访问;




模拟类变量方式 : static 修饰全局变量, 提供一个类方法暴露该全局变量, 并提供一个类方法暴露该全局变量;




代码示例 : 根据上面的示例代码修改而来;



/*************************************************************************
    > File Name: OCPerson.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 三  9/30 09:10:09 2015
 ************************************************************************/
#import <Foundation/Foundation.h>
@interface OCPerson : NSObject
{
  //定义实例变量
  @public
  NSString * _name;
  int _age;
}
/*
 * 声明的 类方法 用于获取类变量
 */
+ (NSString *) getInstance;
/*
 * 声明的 类方法 用于设置类变量
 */
+ (void) setInstance : (NSString *) instanc;
@end
@implementation OCPerson
/*
 * 定义的类变量, 使用 static 修饰全局变量
 */
static NSString * _instance = nil;
/**
 * 获取类变量
 */
+ (NSString *) getInstance
{
  return _instance;
}
/**
 * 设置类变量
 */
+(void) setInstance : (NSString *) instance
{
  _instance = instance;
}
@end
int main(int argc, char * argv[])
{
  @autoreleasepool {
  //创建成员变量
  OCPerson *p =[[OCPerson alloc] init];
  //通过指针变量访问两个实例变量
  NSLog(@"p->_name : %@ , p->_age : %d", p->_name, p->_age);
  //通过指针访问变量为两个成员变量赋值
  p->_name = @"Jim";
  p->_age = 18;
  NSLog(@"p->_name : %@ , p->_age : %d", p->_name, p->_age);
  OCPerson *p1 = [[OCPerson alloc] init];
  OCPerson *p2 = [[OCPerson alloc] init];
  p1->_name = @"Tom";
  p2->_name = @"Keen";
  NSLog(@"p1->_name : %@ , p2->_name : %@", p1->_name, p2->_name);
  [OCPerson setInstance : @"INSTANCE"];
  NSLog(@"instance : %@", [OCPerson getInstance]);
  }
}
-- 执行结果 : 
octopus-2:oc_object octopus$ clang -fobjc-arc -framework Foundation OCPerson.m 
octopus-2:oc_object octopus$ ./a.out 
2015-09-30 10:14:35.235 a.out[2955:507] p->_name : (null) , p->_age : 0
2015-09-30 10:14:35.237 a.out[2955:507] p->_name : Jim , p->_age : 18
2015-09-30 10:14:35.238 a.out[2955:507] p1->_name : Tom , p2->_name : Keen
2015-09-30 10:14:35.238 a.out[2955:507] instance : INSTANCE
octopus-2:oc_object octopus$





3. 单例模式


实现单例 : 定义一个 static 全局变量, 该变量用于保存自己创建的 Singleton 对象, 每次程序获取该单例时, 判断 static singleton 是否为nil, 全局变量为 nil 初始化一个实例并赋值给 static 变量;




单例模式源码示例 :



/*************************************************************************
    > File Name: OCPerson.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 三  9/30 09:10:09 2015
 ************************************************************************/
#import <Foundation/Foundation.h>
@interface OCPerson : NSObject
{
  //定义实例变量
  @public
  NSString * _name;
  int _age;
}
/*
 * 声明的 类方法 用于获取类变量
 */
+ (NSString *) getInstance;
/*
 * 声明的 类方法 用于设置类变量
 */
+ (void) setInstance : (NSString *) instanc;
/**
 * 单例对象获取方法
 */
+ (OCPerson *) getSingleton;
@end
@implementation OCPerson
/*
 * 定义的类变量, 使用 static 修饰全局变量
 */
static NSString * _instance = nil;
/*
 * 定义单例对象类
 */
static OCPerson * singleton = nil;
/**
 * 获取类变量
 */
+ (NSString *) getInstance
{
  return _instance;
}
/**
 * 设置类变量
 */
+(void) setInstance : (NSString *) instance
{
  _instance = instance;
}
/**
 * 获取单例对象
 */
+ (OCPerson *) getSingleton
{
  if(!singleton)
  {
  singleton = [[OCPerson alloc] init];
  }
  return singleton;
}
@end
int main(int argc, char * argv[])
{
  @autoreleasepool {
  //创建成员变量
  OCPerson *p =[[OCPerson alloc] init];
  //通过指针变量访问两个实例变量
  NSLog(@"p->_name : %@ , p->_age : %d", p->_name, p->_age);
  //通过指针访问变量为两个成员变量赋值
  p->_name = @"Jim";
  p->_age = 18;
  NSLog(@"p->_name : %@ , p->_age : %d", p->_name, p->_age);
  /*
   * 创建两个变量
   */
  OCPerson *p1 = [[OCPerson alloc] init];
  OCPerson *p2 = [[OCPerson alloc] init];
  p1->_name = @"Tom";
  p2->_name = @"Keen";
  NSLog(@"p1->_name : %@ , p2->_name : %@", p1->_name, p2->_name);
  /*
   * 设置并获取静态变量
   */
  [OCPerson setInstance : @"INSTANCE"];
  NSLog(@"instance : %@", [OCPerson getInstance]);
  /*
   * 获取两次单例对象, 比较这两个对象是否相等
   */
  NSLog(@"%d", [OCPerson getSingleton] == [OCPerson getSingleton]);
  }
}

-- 执行效果 :


octopus-2:oc_object octopus$ clang -fobjc-arc -framework Foundation OCPerson.m

octopus-2:oc_object octopus$ ./a.out

2015-09-30 10:31:38.935 a.out[2974:507] p->_name : (null) , p->_age : 0

2015-09-30 10:31:38.937 a.out[2974:507] p->_name : Jim , p->_age : 18

2015-09-30 10:31:38.938 a.out[2974:507] p1->_name : Tom , p2->_name : Keen

2015-09-30 10:31:38.939 a.out[2974:507] instance : INSTANCE

2015-09-30 10:31:38.939 a.out[2974:507] 1






三. 隐藏 封装






1. 封装简介





封装 : 面向对象三个特性 封装, 继承, 多态;


-- 概念 : 将对象的 状态信息 隐藏在对象内部, 不允许外界 直接访问内部信息, 外部只能通过 类提供的方法 来实现对内部信息的访问 操作;







2. 访问控制符使用详解



(1) 访问控制符界别范围



访问控制符控制级别 : @private < (@package | @protected) < @public ;


-- @private : 只能在当前类访问, 用于彻底隐藏成员变量, 类实现部分定义的成员变量默认是 @private ;


-- @package : 只能在当前映像访问, 可以在当前类 或者 当前映像的 任意位置访问, 用于部分隐藏成员变量;


-- @protected : 子类访问, 可以在当前类, 子类 任意位置访问, 类接口部分定义的成员变量默认使用 @protected 访问;


-- @public : 可以在任意位置访问;




访问控制符范围 :




@private @package @protected @public

同一个类中 可访问 可访问 可访问 可访问

通映像中

可访问

可访问

子类中


可访问 可访问

全局任意位置



可访问





(2) 访问控制符注意点 和 原则




访问控制符注意点 :


-- 注意 : 访问控制符只能控制成员变量是否可以被其它类访问, 不能用于修饰局部变量;


-- 访问控制符控制范围 : 从访问控制符出现位置开始 到 下一个访问控制符 或者 花括号之间的成员变量;


-- getter 和 setter 方法 : 去掉成员变量的下划线前缀, _name 对应 setName() name();




基本原则 :


-- 修饰成员变量方法 : 类中 99% 的变量都应该使用 @private 控制, 用于辅助实现类其它方法的工具方法也要使用 @private 修饰, 定义在实现类内部;


-- 子类访问 : 父类希望其成员变量能被子类访问, 使用 @protected 控制该成员变量;


-- 接口默认 public 方法 : 暴露给其它类自由调用的方法, 在类接口中定义, 在类实现中实现它们;







(3) 访问控制符源码示例


示例源码 :



/*************************************************************************
    > File Name: OCPerson.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 三  9/30 09:10:09 2015
 ************************************************************************/
#import <Foundation/Foundation.h>
@interface OCPerson : NSObject
{
  /*
  * 定义示例变量, 将这些变量定义成 private 类型
  * 该实例变量只能在 OCPerson.m 中使用
  */
  @private
  NSString * _name;
  int _age;
}
/*
 * 下面得四个方法是存取方法
 */
- (void) setName : (NSString *) name;
- (NSString *) name;
- (void) setAge : (int) age;
- (int) age;
/*
 * 声明的 类方法 用于获取类变量
 */
+ (NSString *) getInstance;
/*
 * 声明的 类方法 用于设置类变量
 */
+ (void) setInstance : (NSString *) instanc;
/**
 * 单例对象获取方法
 */
+ (OCPerson *) getSingleton;
@end
@implementation OCPerson
/*
 * 定义的类变量, 使用 static 修饰全局变量
 */
static NSString * _instance = nil;
/*
 * 定义单例对象类
 */
static OCPerson * singleton = nil;
- (void) setName : (NSString *) name
{
  _name = name;
}
- (NSString *) name
{
  return _name;
}
- (void) setAge : (int) age
{
  _age = age;
}
- (int) age
{
  return _age;
}
/**
 * 获取类变量
 */
+ (NSString *) getInstance
{
  return _instance;
}
/**
 * 设置类变量
 */
+(void) setInstance : (NSString *) instance
{
  _instance = instance;
}
/**
 * 获取单例对象
 */
+ (OCPerson *) getSingleton
{
  if(!singleton)
  {
  singleton = [[OCPerson alloc] init];
  }
  return singleton;
}
@end
int main(int argc, char * argv[])
{
  @autoreleasepool {
  /*
   * 获取单例对象
   */
  OCPerson * p = [OCPerson getSingleton];
  /*
   * 使用 setter 方法设置 _name 和 _age 成员变量
   */
  [p setAge : 18];
  [p setName : @"Tom"];
  /*
   * 使用 getter 方法 age() 和 name() 获取 _age 和 _name 成员变量值
   */
  NSLog(@"name : %@ , age : %d", [p name], [p age]);
  }
}



-- 执行结果 :


octopus-2:oc_object octopus$ clang -fobjc-arc -framework Foundation OCPerson.m 
octopus-2:oc_object octopus$ ./a.out 
2015-09-30 11:45:13.251 a.out[3096:507] name : Tom , age : 18






3. @package 访问控制符简介





常用的访问控制符 : @private 将成员变量限制在当前类内部, @public 彻底暴露成员变量, @protected 让成员变量在子类中可以访问;




映像 : 编译后生成的框架 和 执行文件, 编译后 @package 修饰的成员变量 在这些 框架 和 可执行文件中可以被任意访问;


-- 示例 : 我们之前经常使用类似命令 clang -fobjc-arc -framework Foundation OCPerson.m , 该命令生成一个 a.out 文件, 该 a.out 就是一个映像;







4. 合成存取方法



(1) @property 和 @synthesize 指令




自动 合成 getter 和 setter 方法 :


-- 合成方法 : 接口部分使用 @property 指令定义属性, 如 @property int age; 实现部分使用 @synthesize 声明, 如 @synthesize age;


-- 生成成员变量 : 使用 @property 和 @synthesize 指令声明属性后, 会合成对应的 getter 和 setter 方法, 自动在类实现部分定义一个与 getter 方法同名的成员变量;




@synthesize 指令 : @property NSString * name; @synthesize name = _name;


-- 上面的代码作用 : 使用 @property 合成的存取方法对应的是 _name, 不是 name;


-- @synthesize 语法 : @synthesize propertyName [= fileName];


-- 默认成员变量 : @synthesize  不指定 filedName 时, 成员变量默认为属性名添加下划线; 如 @property NSString * name; @synthesize name; 默认对应的成员变量是 name; 如果 @synthesize name = _name; 默认对应的成员变量是 _name;






示例源码 :



/*************************************************************************
    > File Name: OCPerson.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 三  9/30 09:10:09 2015
 ************************************************************************/
#import <Foundation/Foundation.h>
@interface OCPerson : NSObject
/*
 * 定义示例变量, 将这些变量定义成 private 类型
 * 该实例变量只能在 OCPerson.m 中使用
 */
@property (nonatomic) NSString * name;
@property int age;
/*
 * 声明的 类方法 用于获取类变量
 */
+ (NSString *) getInstance;
/*
 * 声明的 类方法 用于设置类变量
 */
+ (void) setInstance : (NSString *) instanc;
/**
 * 单例对象获取方法
 */
+ (OCPerson *) getSingleton;
@end
@implementation OCPerson
/*
 * 定义的类变量, 使用 static 修饰全局变量
 */
static NSString * _instance = nil;
/*
 * 定义单例对象类
 */
static OCPerson * singleton = nil;
/*
 * 如果 没有后面的 = _name 和 = _age 提示,默认的成员变量 是 name 和 age
 * 当前设置对应的默认成员变量是 _name 和 _age
 */
@synthesize name = _name;
@synthesize age = _age;
- (void) setName : (NSString *) name
{
  //默认的成员变量是 _name
  self->_name = [NSString stringWithFormat : @"++%@++", name];
}
/**
 * 获取类变量
 */
+ (NSString *) getInstance
{
  return _instance;
}
/**
 * 设置类变量
 */
+(void) setInstance : (NSString *) instance
{
  _instance = instance;
}
/**
 * 获取单例对象
 */
+ (OCPerson *) getSingleton
{
  if(!singleton)
  {
  singleton = [[OCPerson alloc] init];
  }
  return singleton;
}
@end
int main(int argc, char * argv[])
{
  @autoreleasepool {
  /*
   * 获取单例对象
   */
  OCPerson * p = [OCPerson getSingleton];
  /*
   * 使用 setter 方法设置 _name 和 _age 成员变量
   */
  [p setAge : 18];
  [p setName : @"Tom"];
  /*
   * 使用 getter 方法 age() 和 name() 获取 _age 和 _name 成员变量值
   */
  NSLog(@"name : %@ , age : %d", [p name], [p age]);
  }
}

-- 执行结果 :


octopus-2:oc_object octopus$ ./a.out 
2015-09-30 13:29:26.323 a.out[3198:507] name : ++Tom++ , age : 18







5. @Property 特殊指示符




(1) assign 特殊指示符



assign 指示符 :


-- 作用 : 指定对属性只是简单赋值, 不更改引用计数, 主要适用于 NSInteger int short double 结构体 等数据类型;


-- 引用计数 : 对象的引用计数大于 0 时, 该对象不会被回收, 基础数据类型不存在回收问题, 可以使用 assign 指示符;






(2) atomic (nonatomic) 特殊指示符



atomic (nonatomic) 指示符 :


-- 作用 : 指定合成的存取方法是否是原子操作, 即线程是否安全;


-- atomic : 合成的存取方法都是线程安全的, 一个线程调用存取方法时, 其它方法无法调用存取方法, 避免多线程并发破坏对象的数据完整性;


-- nonatomic : 用于提高存取方法的访问性能, atomic 线程安全会造成性能下降;







(3) copy 特殊指示符



copy 指示符 :


-- 作用 : 如果使用 copy 指示符, 当调用 setter 方法对成员变量赋值时, 现将被赋值对象复制一个副本, 再将该副本赋给成员变量;


-- 引用计数 : copy 会将原成员变量所引用计数 -1;


-- 适用情况 : 成员变量类型是指针类型时, 被赋值的对象有可能在赋值之后被修改, 如果不想让被赋值对象被修改影响成员变量, 可以使用 copy 指示符;


-- 代码示例 :



/*************************************************************************
    > File Name: OCPerson.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 三  9/30 09:10:09 2015
 ************************************************************************/
#import <Foundation/Foundation.h>
@interface OCPerson : NSObject
/*
 * 定义示例变量, 将这些变量定义成 private 类型
 * 该实例变量只能在 OCPerson.m 中使用
 */
@property (nonatomic) NSString * name;
@property (nonatomic, copy) NSString * describe;
@property int age;
@end
@implementation OCPerson
/*
 * 如果 没有后面的 = _name 和 = _age 提示,默认的成员变量 是 name 和 age
 * 当前设置对应的默认成员变量是 _name 和 _age
 */
@synthesize name = _name;
@synthesize describe = _describe;
@synthesize age = _age;
@end
int main(int argc, char * argv[])
{
  @autoreleasepool {
  //初始化对象
  OCPerson * p = [[OCPerson alloc] init];
  //创建一个字符串
  NSMutableString *str = [NSMutableString stringWithString : @"Tom"];
  //将字符串设置给对象的 name 属性
  [p setName:str];
  [p setDescribe:str];
  //打印出name成员变量值
  NSLog(@"1.name : %@, describe : %@", [p name], [p describe]);
  //修改被赋值的对象
  [str appendString : @" Hax"];
  //打印出name成员变量值
  NSLog(@"2.name : %@, describe : %@", [p name], [p describe]);
  }
}


-- 执行结果 :


octopus-2:oc_object octopus$ clang -fobjc-arc -framework Foundation OCPerson.m 
octopus-2:oc_object octopus$ ./a.out 
2015-09-30 18:05:48.170 a.out[3295:507] 1.name : Tom, describe : Tom
2015-09-30 18:05:48.172 a.out[3295:507] 2.name : Tom Hax, describe : Tom




(4) getter setter 特殊指示符


getter(setter) 指示符 :


-- 作用 : getter 和 setter 方法指定自定义方法名;


-- 示例 : getter = han 指定 getter 方法为 han, setter = octopus 指定 setter 方法为 octopus;


-- 源码示例 :



/*************************************************************************
    > File Name: OCPerson.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 三  9/30 09:10:09 2015
 ************************************************************************/
#import <Foundation/Foundation.h>
@interface OCPerson : NSObject
/*
 * 定义示例变量, 将这些变量定义成 private 类型
 * 该实例变量只能在 OCPerson.m 中使用
 */
@property (nonatomic) NSString * name;
@property (nonatomic, copy) NSString * describe;
@property (assign, nonatomic, getter = han, setter = octopus:) int age;
@end
@implementation OCPerson
/*
 * 如果 没有后面的 = _name 和 = _age 提示,默认的成员变量 是 name 和 age
 * 当前设置对应的默认成员变量是 _name 和 _age
 */
@synthesize name = _name;
@synthesize describe = _describe;
@synthesize age = _age;
@end
int main(int argc, char * argv[])
{
  @autoreleasepool {
  OCPerson * p = [[OCPerson alloc] init];
  NSMutableString *str = [NSMutableString stringWithString : @"Tom"];
  [p setName:str];
  [p setDescribe:str];
  NSLog(@"1.name : %@, describe : %@", [p name], [p describe]);
  [str appendString : @" Hax"];
  NSLog(@"2.name : %@, describe : %@", [p name], [p describe]);
  [p octopus:18];
  NSLog(@"age : %d", [p han]);
  }
}


-- 执行结果 :


octopus-2:oc_object octopus$ clang -fobjc-arc -framework Foundation OCPerson.m 
octopus-2:oc_object octopus$ ./a.out 
2015-09-30 18:28:16.132 a.out[3329:507] 1.name : Tom, describe : Tom
2015-09-30 18:28:16.135 a.out[3329:507] 2.name : Tom Hax, describe : Tom
2015-09-30 18:28:16.135 a.out[3329:507] age : 18


(5) readonly readwrite 特殊指示符


readonly : 系统只合成 getter 方法, 不再合成 setter 方法;


readwrite : 需要合成 setter getter 方法;





(6) retain 特殊指示符


retain :


-- 作用 : retain 定义属性, 将某个对象赋值给该属性时, 该属性原来所引用的对象引用计数 -1, 被赋值对象 (成员变量) 引用计数 +1;


-- 使用场景 : 在未启用 ARC 机制情况下, 常用, 启用后不常用;


-- 源码示例 : 不能使用 @autoreleasepool ARC 机制, 需要关闭该机制;



/*************************************************************************
    > File Name: OCPerson.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 三  9/30 09:10:09 2015
 ************************************************************************/
#import <Foundation/Foundation.h>
@interface OCPerson : NSObject
@property (nonatomic, retain) NSDate * date;
@end
@implementation OCPerson
@synthesize date;
@end
int main(int argc, char * argv[])
{
  OCPerson * p = [[OCPerson alloc] init];
  NSDate * date = [[NSDate alloc] init];
  NSLog(@"date retainCount : %ld, _date retainCount : %ld", date.retainCount, [p date].retainCount);
  [p setDate : date];
  NSLog(@"date retainCount : %ld, _date retainCount : %ld", date.retainCount, [p date].retainCount);
  [date release];
  NSLog(@"date retainCount : %ld, _date retainCount : %ld", date.retainCount, [p date].retainCount);
}
-- 执行结果 : 注意编译时不能使用 -fobjc-arc 参数;
octopus-2:oc_object octopus$ clang -framework Foundation OCPerson.m 
octopus-2:oc_object octopus$ ./a.out 
2015-09-30 18:59:11.602 a.out[3400:507] date retainCount : 1, _date retainCount : 0
2015-09-30 18:59:11.604 a.out[3400:507] date retainCount : 2, _date retainCount : 2
2015-09-30 18:59:11.605 a.out[3400:507] date retainCount : 1, _date retainCount : 1




(7) strong weak 特殊指示符


strong 指示符 : 指定该属性对赋值对象持有强引用, 只要该强引用指向被赋值的对象, 那么该对象就不会自动回收;


weak 指示符 : 指定该属性对被赋值对象持有弱引用, 弱引用指向被赋值的对象, 该对象可能被回收;





(8) unsafe_unretained 特殊指示符


unsafe_unretained 指示符 : 与 weak 指示符基本相似, 对于被 unsafe_unretained 指向的对象也可能会被回收; 被 unsafe_unretained 修饰的指示的指针变量, 该指针不会被赋值为 nil, 可能导致程序崩溃;







5. 使用 . 语法访问属性



(1) 变量分类



点 . 使用 :


-- 使用前提 : 使用 @property @synthesize 合成 setter 和 getter 方法; 实际上 也允许使用 . 语法访问属性 和 对属性赋值;


-- 本质 : 点语法是一种简单写法, 其本质仍然是 getter 和 setter 方法;


-- 获取属性值 : 只要对象有 getter 方法, 程序可以使用 点 语法获取属性值;


-- 设置属性值 : 只要对象 setter 方法, 程序可以使用 点 语法获取属性值;


-- 源码示例 :



/*************************************************************************
    > File Name: OCPerson.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 三  9/30 09:10:09 2015
 ************************************************************************/
#import <Foundation/Foundation.h>
@interface OCPerson : NSObject
@property (nonatomic, copy) NSString * name;
@property (nonatomic, assign) int age;
@end
@implementation OCPerson
@synthesize name;
@synthesize age;
@end
int main(int argc, char * argv[])
{
  @autoreleasepool
  {
  OCPerson * p = [[OCPerson alloc] init];
  p.name = @"Tom";
  p.age = 18;
  NSLog(@"name : %@, age : %d", p.name, p.age);
  }
}
-- 执行结果 : 
octopus-2:oc_object octopus$ clang -fobjc-arc -framework Foundation OCPerson.m 
octopus-2:oc_object octopus$ ./a.out 
2015-09-30 19:34:59.849 a.out[3451:507] name : Tom, age : 18






四. 键值编码 (KVC)




1. 简单地 KVC



(1) KVC 简介




KVC 简介 :


-- 引入 : Object-C 可以通过 getter setter 方法操作属性, 还可以 以字符串形式间接操作属性, 该方式是 Key Value Coding (KVC);


-- KVC 使用前提 : 最好在接口部分使用 @property 实现类部分使用 @synthesize 合成存取方法, 也可以只定义 "_属性名" 或 "属性名" 成员变量, 之后才能成功使用 KVC;




操作属性方法 :


-- 未指定属性设定值 : "setValue : 属性值 forKey : 属性名" ;


-- 获取指定属性值 : "valueForKey : 属性名" ;




(2) setValue : forKey 执行机制



"setValue : 属性值 forKey 属性名" 执行机制 :


-- 调用 setter 方法 : 优先考虑调用 "setName : 属性值", 通过 setter 方法完成赋值;


-- 寻找 "_属性名" 变量 : 如果没有 setter 方法, 系统会搜索 "_属性名" 成员变量, 只要有 "_属性名" 成员变量, 无论实在 接口 还是在实现类定义, 无论使用什么访问控制符, 系统都会对该变量赋值;


-- 寻找 "属性名" 变量 : 如果既没有 setter 方法, 也没有 "_属性名" 成员变量, 系统会搜索 "属性名" 成员变量, 不管定义在什么位置(接口 实现), 也不管是用什么访问控制符修饰的, 系统都会对该变量赋值;


-- 引发异常 : 上面三种都没有成功, 系统执行 该对象的 "setValue : forUndefinedKey : " 方法;





(3) valueForKey : 执行机制


"valueForKey : 属性名" 执行机制 :


-- 调用 getter 方法 : 优先考虑调用 getter 方法, 即 属性名() 方法获取返回值;


-- 寻找 "_属性名" 成员变量 : 如果没有 getter 方法, 系统会搜索 "_属性名" 成员变量, 不管该成员变量的定义位置 和 用什么访问控制符修饰, 都返回该 "_属性名" 成员变量值;


-- 寻找 "属性名" 成员变量 : 如果既没有找到 getter 方法, 也没有找到 "_属性名" 成员变量, 系统会搜索 "属性名" 成员变量, 不管该成员变量的定义位置 和 用什么访问控制符修饰, 都返回 "属性名" 成员变量的值;


-- 引发异常 : 上面三种都没有成功, 系统会执行对象的 "valueForUndefinedKey :";





(4) KVC 简单用法源码示例


源码示例 :



/*************************************************************************
    > File Name: OCPerson.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 三  9/30 09:10:09 2015
 ************************************************************************/
#import <Foundation/Foundation.h>
@interface OCPerson : NSObject
{
  @private 
  int _age;
  @public 
  NSString * family;
}
@property (nonatomic, copy) NSString * name;
@end
@implementation OCPerson
@synthesize name;
@end
int main(int argc, char * argv[])
{
  @autoreleasepool
  {
  OCPerson * p = [[OCPerson alloc] init];
  [p setValue : @"Tom" forKey : @"name"];
  [p setValue : [NSNumber numberWithInt : 18] forKey : @"age"];
  [p setValue : @"Hax" forKey : @"family"];
  NSLog(@"name : %@, age : %@, family : %@", 
    [p valueForKey : @"name"], 
    [p valueForKey : @"age"],
    [p valueForKey : @"family"]);
  }
}



-- 执行结果 :


octopus-2:oc_object octopus$ clang -fobjc-arc -framework Foundation OCPerson.m 
octopus-2:oc_object octopus$ ./a.out 
2015-09-30 21:59:44.909 a.out[3566:507] name : Tom, age : 18, family : Hax


相关实践学习
云安全基础课 - 访问控制概述
课程大纲 课程目标和内容介绍视频时长 访问控制概述视频时长 身份标识和认证技术视频时长 授权机制视频时长 访问控制的常见攻击视频时长
目录
相关文章
|
1天前
|
iOS开发 开发者 UED
探索iOS开发中的SwiftUI框架
【6月更文挑战第28天】在移动应用开发的海洋中,SwiftUI作为iOS平台的新星,以其声明式语法和灵活性,正引领着界面设计的未来。本文将带你深入理解SwiftUI的核心概念、布局能力以及如何通过它提升开发效率,为开发者们提供一份实操指南,解锁SwiftUI的强大潜力。
8 1
|
4天前
|
监控 Android开发 iOS开发
探索Android与iOS开发的差异:平台、工具和用户体验的比较
【6月更文挑战第25天】在移动应用开发的广阔天地中,Android和iOS两大平台各领风骚,它们在开发环境、工具选择及用户体验设计上展现出独特的风貌。本文将深入探讨这两个操作系统在技术实现、市场定位和用户交互方面的关键差异,旨在为开发者提供一个全景式的视图,帮助他们在面对项目决策时能够更加明智地选择适合自己项目需求的平台。
|
2天前
|
安全 Android开发 iOS开发
探索安卓与iOS开发的差异:平台特性与用户体验的深度对比
在移动应用开发的广阔天地中,安卓和iOS两大平台各占半壁江山。本文旨在通过数据驱动的分析方法,深入探讨这两大操作系统在开发环境、用户界面设计及市场表现等方面的差异。引用最新的行业报告和科研数据,结合技术专家的观点,本文将提供对开发者和市场分析师均有价值的洞见。
|
3天前
|
缓存 C语言 iOS开发
一篇文章讲明白iOS开发系列
一篇文章讲明白iOS开发系列
|
4天前
|
设计模式 IDE Swift
探索iOS开发:从新手到专家的旅程
【6月更文挑战第25天】在数字时代的浪潮中,iOS开发作为一门艺术和科学的结合体,吸引了众多开发者的目光。本文将带领读者踏上一场精彩的旅程,从基础的搭建环境开始,逐步深入到高级编程技巧,再到应用发布与市场策略,全方位解读iOS开发的魅力所在。通过实际案例分析,我们将揭示那些让应用脱颖而出的秘密,以及如何在竞争激烈的应用市场中保持竞争力。无论你是初学者还是有经验的开发者,这篇文章都将为你提供宝贵的见解和实用的技巧,让你的iOS开发之旅更加顺畅。
|
Android开发 iOS开发
IOS隐藏键盘
最近遇到二个键盘会自动弹出的问题: 1、UIWebView加载网页后,点击网页内的链接在UIWebView内进行跳转时,键盘自动弹起; 2、调用选择照片时,iPod上选择照片后也会自动弹出键盘,比如从图库进到具体某个文件夹内,或者再返回图库,直接点中照片然后编辑的时候,都会自动弹出;   问...
929 0
|
5天前
|
Java 开发工具 Android开发
探索Android与iOS开发的差异:平台选择对项目成功的影响
在移动应用开发的广阔天地中,Android和iOS两大平台各自占据着半壁江山。本文将深入探讨这两个平台在开发过程中的关键差异点,包括编程语言、开发工具、用户界面设计、性能优化以及市场覆盖等方面。通过对这些关键因素的比较分析,旨在为开发者提供一个清晰的指南,帮助他们根据项目需求和目标受众做出明智的平台选择。
|
5天前
|
编解码 Android开发 iOS开发
深入探索Android与iOS开发的差异与挑战
【6月更文挑战第24天】在移动应用开发的广阔舞台上,Android和iOS两大操作系统扮演着主角。它们各自拥有独特的开发环境、工具集、用户基础及市场策略。本文将深度剖析这两个平台的开发差异,并探讨开发者面临的挑战,旨在为即将踏入或已在移动开发领域奋斗的开发者提供一份实用指南。
27 13
|
8天前
|
iOS开发 开发者 容器
探索iOS开发中的SwiftUI框架
【6月更文挑战第21天】本文深入探讨了苹果在iOS开发中推出的SwiftUI框架,旨在为开发者提供一种声明式、更简洁的界面设计方法。文章首先概述了SwiftUI的核心概念和优势,接着通过一个天气预报应用实例,详细讲解了如何使用SwiftUI进行布局和用户界面的设计。此外,还讨论了SwiftUI与UIKit的差异,以及如何将SwiftUI集成到现有的项目中。最后,文章展望了SwiftUI的未来发展方向,包括潜在的改进和新特性。