【IOS学习基础】OC类的相关
几天前突然在别人的类的.m文件中看到这么一句代码:@synthesize xxxx = _xxxx; 当时愣是没理解啥意思,过后才缓过神来发现原来是把一些类的基础知识忘记了,虽然不用过多去深究以前的一些旧东西,但但是既然遇到了,还是复习一下。
一、类与对象
1.类:类是定义同一类所有属性和方法的蓝图或原型。
2.对象:用来描述客观事物的一个实体,由具体的属性和方法构成。
3.类与对象的关系:类是用来制作无数实体(对象)的工程图纸。
4.类的特征:属性
5.类的行为:方法
二、封装
1.类就是封装,封装了属性与方法。它是一种思想,其核心就是“暴露出必要的内容给外部用(属性方法私有),而对于内部细节,使用者不用去关心”。
我们声明一个Teacher类:
#import <Foundation/Foundation.h>
@interface Teacher : NSObject
{
// @public 公共的
NSString *_name; //成员变量(实例变量) 默认@protected修饰(受保护的) /* 顺带一提:@protected、@public、@private、@package
* @public 成员变量可以被在任何地方访问。
* @protected 成员变量能被声明它的类和子类访问(默认)
* @private 成员变量只能在声明它的类中访问(默认现在用@Property关键字生成的成员变量是这个)
* @package 一个@package成员变量在实现这个类的可执行文件镜像中实际上是@public的,但是在外面就是@private。
*/
}@end
然而,我们此时在外面根本无法访问到这个受保护的成员变量。
访问该成员变量的方法:
1> 打开上面 “@public”的注释,在外面以"->“方式访问
Teacher *tec = [[Teacher alloc] init];
tec->_name = @"姓名";
2> 封装set、get方法进行间接访问,在.h文件中加上方法声明,在.m文件中实现
-(void)setName:(NSString *)name;
-(NSString *)getName; -(void)setName:(NSString *)name
{
_name = name;
}
-(NSString *)getName
{
return _name;
}
这样,便可以在外面通过调用方法的方式来间接访问该成员变量,其实下面讲的@property关键字就是帮你解决了这个set、get方法的访问
让其在外面以"."的方式(本质上是调用set和get方法)间接访问。
Teacher *tec = [[Teacher alloc] init];
[tec setName:@"testName"];
NSLog(@"%@",[tec getName]);
总结一下成员变量和成员属性:
①成员变量即实例变量
②成员属性用于间接访问类中的成员变量
③假如你想让类的一个特性私有,只在本类访问,就定义成成员变量;假如你想在类之外访问该类的一个特性,你就将其定义成成员属性。
三、@property和@synthesize关键字
1.在以前,我们经常可以看到这种类的声明
#import <Foundation/Foundation.h> @interface Teacher : NSObject
{
NSString *_name; //成员变量
}
@property (nonatomic,copy)NSString *name; //成员属性 @end #import "Teacher.h" @implementation Teacher @synthesize name = _name; @end
这是在之前的编译器特性中:
@property帮我们声明了name属性的set和get方法
@synthesize name = _name则表示对@property声明的属性name实现set和get方法,后面的” = _name“表示实现的时候访问成员变量_name
2.而现在我们为类声明一个属性则通常只需要一句话(我一般都用这种,方便):
@property (nonatomic,copy)NSString *name; //这里指在.h文件中声明
这是在新的编译器特性中:
@property直接帮助我们干了三件事:
①当该name属性的成员变量未被指定时,会生成一个默认为_name的成员变量,但是该属性为@private(私有的),自己写的则是@protected(受保护的)
②声明name属性的set、get方法
③实现name属性的set、get方法
注:如果你想要用自己生成的成员变量,则用之前的那种格式,在.h文件中增加一个成员变量,在.m文件中加上@synasize xxx = _xxx。
成员变量用”_“下划线开头命名的好处:
①区分成员变量和属性
②防止局部变量和成员变量命名冲突
四、关于继承的几句话
1.继承:建立类之间的关系,实现代码的重用性,方便系统扩展。
2.继承是为了避免多个相似的类中相同的成员变量反复定义而延伸的一个特性。
3.继承有单根性与传递性
4.被继承的类称之为父类或基类,继承的类称之为子类或派生类
5.super关键字:self用于访问本类成员,而super则是用于在子类中访问父类成员
五、分类catagory
分类:①在不改变原来类的基础上,为类增加一些方法,来对类进行一个扩展。
②在开发中,我们一般对都是为系统提供的类添加分类。还有就是将自己的类分模块,将实现不同功能的方法写在不同的分类中,一个类可以有无限个分类。
1.分类又称为非正式协议:NSObject类及其子类的一个类别(catagory)。
#import "Teacher.h" @interface Teacher (Log)
+(void)log;
@end #import "Teacher+Log.h" @implementation Teacher (Log)
+(void)log
{
NSLog(@"分类");
}
@end
如上面所写的分类,我们为Teacher类添加了一个分类"Teacher+Log.h",分类中声明并实现了类方法+(void)log;
2.类的延展:匿名分类。
在Teacher.m文件中
#import "Teacher.h" @interface Teacher () //这种写法就是匿名分类 @property (nonatomic,copy)NSString *nickName; //匿名分类中可以添加属性,但是该属性默认为@private,只能在本类中使用 +(void)log; //声明了一个类方法log @end @implementation Teacher @synthesize name = _name;
//实现该类方法
+(void)log
{
NSLog(@"匿名分类");
} @end
接着我们调用log方法,出现如下打印
这里证明:分类(非正式协议)会重写本类及其类扩展(匿名分类)的方法。
3.catagory中匿名分类允许添加属性并会自动生成成员变量和set、get方法;但是在非正式协议中,允许你用@property声明一个属性,不会为你提供set、get方法以及成员变量,如果你直接使用的话,造成崩溃。如下
1> 我为Teacher + MyProperty.h分类头文件中增加了一个属性nickName;
#import "Teacher.h" @interface Teacher (MyProperty) @property (nonatomic,copy)NSString *nickName; @end
2>使用(缺少set、get方法导致崩溃)
Teacher *tec = [[Teacher alloc] init];
tec.nickName = @"nickNmae";
NSLog(@"%@",tec.nickName); // 打印
-- ::13.656 分类[:] -[Teacher setNickName:]: unrecognized selector sent to instance 0x100213e10
-- ::13.658 分类[:] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Teacher setNickName:]: unrecognized selector sent to instance 0x100213e10'
*** First throw call stack:……
3>如何在非正式协议(分类)中添加属性【oc针对这一现象,提供了一个解决方案:关联对象(Associated Object)】,在分类的.m文件中写上如下代码
#import "Teacher+MyProperty.h"
#import <objc/runtime.h> static void *strKey = &strKey; @implementation Teacher (MyProperty) -(void)setNickName:(NSString *)nickName
{
objc_setAssociatedObject(self, &strKey, nickName, OBJC_ASSOCIATION_COPY);
} -(NSString *)nickName
{
return objc_getAssociatedObject(self, &strKey);
} @end
六、协议protocol
1.有非正式协议,自然也有正式协议,protocol便是,用于声明一大堆方法,等待实现,只要某个类遵守了某个协议,那么这个类就拥有了该协议的所有方法声明。(注意:协议只存在.h声明文件)其格式如下:
@protocol Teach <NSObject>
@required;
-(void)teach:(NSString *)text; // 声明了一个teach的方法,并且为必须实现,默认是@optional; @end //新建了一个名为Teach.h的协议头文件
2.类可以遵守协议(Teacher遵守teach协议)
3.实现方法
-(void)teach:(NSString *)text
{
NSLog(@"老师教书");
}
4.一个类只能继承自一个父类(继承的单根性),但是一个类可以遵守多份协议.
七、关联对象(Associated Object)--扩展
1.关联对象类似于成员变量,但是它是在运行时被添加的。(用于解决分类中添加属性的问题,上面已经介绍了原因,这里不做介绍)
2.我们可以把关联对象想象成一个OC对象,这个对象通过key连接到一个类的实例变量上。
3.由于使用的是C接口,所以key是一个void指针(const void *)。我们还需要指定一个内存管理策略,以告诉Runtime如何管理这个对象的内存。内存管理策略选项值如下:
// 当宿主对象被释放时,会根据指定的内存管理策略来处理关联对象。当我们需要在多个线程中处理访问关联对象的多线程代码时,这就非常有用了
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
OBJC_ASSOCIATION_ASSIGN = ,
OBJC_ASSOCIATION_RETAIN_NONATOMIC = ,
OBJC_ASSOCIATION_COPY_NONATOMIC = ,
OBJC_ASSOCIATION_RETAIN = ,
OBJC_ASSOCIATION_COPY =
};
/* 如果指定的策略是assign,则宿主释放时,关联对象不会被释放;
而如果指定的是retain或者是copy,则宿主释放时,关联对象会被释放。
我们甚至可以选择是否是自动retain/copy。
*/
4.使用
1> void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)方法:将一个对象连接到其它对象
参数1:源对象,一般传self.
参数2:key,用来表示是哪一属性的key,可能在分类中添加不止一个属性。
常见有三种写法:
① static void *strKey = &strKey;
②
static NSString *strKey = @"strKey";
③ static char strKey;
参数3:关联的对象
参数4:关联策略
self对象将获取一个新的关联的对象anObject,且内存管理策略是自动retain关联对象,当self对象释放时,会自动release关联对象。另外,如果我们使用同一个key来关联另外一个对象时,也会自动释放之前关联的对象,这种情况下,先前的关联对象会被妥善地处理掉,并且新的对象会使用它的内存。
2> id anObject = objc_getAssociatedObject(self, &myKey)方法 ,获取关联的对象
3> objc_removeAssociatedObjects(self)方法,移除所有关联
5、应用(UIAlertView + Block分类,以自身为delegate监控选项按钮点击事件,以block作为关联对象)
#import <UIKit/UIKit.h>
typedef void(^CompleteBlock) (NSInteger buttonIndex); @interface UIAlertView (Block) // 用Block的方式回调,这时候会默认用self作为Delegate
- (void)showAlertViewWithCompleteBlock:(CompleteBlock) block; @end #import "UIAlertView+Block.h"
#import <objc/runtime.h> @implementation UIAlertView (Block) static char key; // 用Block的方式回调,这时候会默认用self作为Delegate
- (void)showAlertViewWithCompleteBlock:(CompleteBlock)block
{
if (block) {
//移除所有关联
objc_removeAssociatedObjects(self);
/**
1 创建关联(源对象,关键字,关联的对象和一个关联策略。)
2 关键字是一个void类型的指针。每一个关联的关键字必须是唯一的。通常都是会采用静态变量来作为关键字。
3 关联策略表明了相关的对象是通过赋值,保留引用还是复制的方式进行关联的;关联是原子的还是非原子的。这里的关联策略和声明属性时的很类似。
*/
objc_setAssociatedObject(self, &key, block, OBJC_ASSOCIATION_COPY);
//设置delegate
self.delegate = self;
}
[self show];
} - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
///获取关联的对象,通过关键字。
CompleteBlock block = objc_getAssociatedObject(self, &key);
if (block) {
///block传值
block(buttonIndex);
}
}
/**
OC中的关联就是在已有类的基础上添加对象参数。来扩展原有的类,需要引入#import <objc/runtime.h>头文件。关联是基于一个key来区分不同的关联。
常用函数:
objc_setAssociatedObject 设置关联
objc_getAssociatedObject 获取关联
objc_removeAssociatedObjects 移除关联
*/
//当然也可以不必这么麻烦,使用继承同样可以轻易做到。
@end
八、类的加载(认识两个方法)
/**
* 这两个方法是在程序运行一开始就被调用的方法.
* 我们可以利用他们在类被使用前,做一些预处理工作.
* 比如我碰到的就是让类自动将自身类名保存到一个NSDictionary中.
*/ //而initialize是在类或者其子类的第一个方法被调用前调用。
+(void)initialize; //load方法是只要类所在文件被引用就会被调用.
+(void)load; /**
* 所以如果类没有被引用进项目,就不会有load调用;
* 但即使类文件被引用进来,但是没有使用,那么initialize也不会被调用
*/
九、反射
1.反射:简而言之就是通过类名返回类的对象(使用前导入#import <objc/runtime.h>头文件,今天前面的关联对象也用到这个头文件,好像关于这个runtime要学的东西有点多,复习着一下子扒出了好多要学的新东西,- _ -,先从基础的慢慢来吧)
// 类名返回类对象
+(NSObject *)createBean:(NSString *)className
{
Class tempClass = NSClassFromString(className);
NSObject *obj;
if (tempClass)
{
obj = [[tempClass alloc]init];
}
return obj;
}
2.类名得到属性名集合
+(NSArray *)propertyOfClass:(NSString *)className
{
NSMutableArray *arr = [NSMutableArray arrayWithCapacity:];
//通过类名获得类的属性
const char *cClassName = [className UTF8String]; id theClass = objc_getClass(cClassName); unsigned int outCount, i; objc_property_t *properties = class_copyPropertyList(theClass, &outCount);
for (i = ; i < outCount; i++)
{
objc_property_t property = properties[i];
NSString *propertyNameString = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
[arr addObject:propertyNameString];
}
return arr;
}
3.通过反射(结合KVC),通过类名、数据源、约定,我们就可以实现json字符串转对象。
4.具体之后三方库学习MJExtension中NSObject + MJClass转模型。
十、类簇
1.类簇是Foundation框架中广泛使用的设计模式(抽象工厂模式)。类簇将一些私有的、具体的子类组合在一个公共的、抽象的超类下面,以这种方法来组织类可以简化一个面向对象框架的公开架构,而又不减少功能的丰富性。
2.类簇的概念(选自百度百科。。。)
类簇 是一群隐藏在通用接口下的与实现相关的类,使得我们编写的代码可以独立于底层实现(因为接口是稳定的)。
如创建NSString对象时,你得到的可能是NSLiteralString,NSCFString,NSSimpleCString等。即不同的NSString对象调用同一个接口A,接口A的实现可能是不同的。
在Foundation框架中,常见的类簇有NSNumber,NSString,NSArray,NSDictionary等。 想要在类簇中创建子类会困难一些,必须是抽象超类的子类,必须重载超类的原始方法,必须声明自己的数据存储。最方便的是使用组合或者类别来代替子类化。
3.关于重写init方法时候调用父类的init方法:self = [super init]和[super init]
咋看之下,产生了一个疑问,为什么[super init]要赋值给self。今天看了下类簇的概念,终于明白了,由于在有些情况下,init可能会改变返回的对象,这时候必须赋值给self。
4、不推荐继承类簇
当你继承某个类簇的超类之后,子类可以使用父类的方法,结果你去调用该类簇的超类的方法,你会发现程序崩溃了,原因是由于在超类的方法的实现里,你不知道它实际调用的它里面的哪一个子类的方法(这些组合的子类声明和实现都隐藏在该超类的.m文件里面),结果你的类是直接继承自该类簇的超类,也就是说你的类根本就不认识这个方法。
【IOS学习基础】OC类的相关的更多相关文章
- 【IOS学习基础】NSObject.h学习
一.<NSObject>协议和代理模式 1.在NSObject.h头文件中,我们可以看到 // NSObject类是默认遵守<NSObject>协议的 @interface N ...
- JAVA基础2——类初始化相关执行顺序
类初始化相关执行顺序 几个概念说明 代码块的含义与作用 static静态代码块: 一般用于初始化类中的静态变量.比如:给静态的数组或者list变量赋初值.使用static静态代码块进行初始化与直接在定 ...
- 【IOS学习基础】文件相关
一.沙盒(SandBox) 1.沙盒机制 1> 每个应用都有属于自己的存储空间,即沙盒. 2> 应用只能访问自己的沙盒,不可访问其他区域. 3> 如果应用需要进行文件操作,则必须将文 ...
- iOS学习笔记---oc语言第四天
字符串 数组 一.使用苹果帮助文档 学会使⽤用苹果帮助⽂文档是开发者的⼀一项技能 Inherits from 继承⾃自 Conforms to 遵循什么协议 Framework 属于哪个框架 Avai ...
- iOS学习笔记---oc语言第五天
字典,数组 ,集排序 一.字典类 存储以下数据 name:张三; sex:男;age:18 film:风暴; playcount:10000次;price:60元 字典类用于保存具有映射关系(key- ...
- iOS学习笔记---oc语言第三天
继承.初始化方法 一.继承 继承的上层:父类 继承的下层:子类 继承是单向的,不能相互继承 继承具有传递性:A继承于B,B继承于C,A具有B和C的特征和行为 子类能继承父类全部的特征和行为(私有变量 ...
- iOS学习笔记--OC系列(1)
前言 从学校毕业进入公司工作已经第3个年头了,回顾这3年的经历,有种迷茫的感觉.在公司我主要是做零售业公司的系统维护,接触的主要是Oracle的Database的东西.但是业务知识和oracle,都没 ...
- 【IOS学习基础】归档和解档
一.归档介绍 1.归档是指用某种格式来保存一个或多个对象,以便以后还原这些对象的过程.归档是将数据持久化的一种方式(所谓数据持久化,就是指在IOS开发过程中,将数据保存到本地,能够让程序的运行更加流畅 ...
- 【IOS学习基础】内存管理
1.内存几大区域 1> 栈区:局部变量(基本数据类型.指针变量). 2> 堆区:程序运行的过程中动态分配的存储空间(创建的对象). 3> BSS段:没有初始化的全局变量和静态变量. ...
随机推荐
- 项目总结之MIT (一)
打开Plan才知道,原来这个项目伴随了我整个八月,做项目的时间果然特别快~~ 首先把之前出现但是只知其然但是不知其所以然的知识点总结一下 一.使用母版页 二.Ajax 控件 & Custome ...
- android第三方分享之友盟社会化组件
前言 现在几乎所有的app都带有分享功能,第一为了更好地推广自己的产品,第二作为使用者也能及时的把自己觉得好的文章,话题,app分享到社交平台供大家一起学习和使用.开发中虽然android系统自带分享 ...
- 实现android4.4新特性:沉浸式状态栏
先放效果图: 所谓沉浸式状态栏,就是android4.4以后新加入的ui效果,能使最顶部的状态栏自动适宜app顶部的颜色,使两者看起来更像融为一体.下面放上实现代码: requestWindowFea ...
- java学习——数组
元素类型[] 数组名 = new 元素类型[元素个数或数组长度]; array 为引用数据类型|-数组数据类型 | 内存结构:程序在运行时,需要在内存中的分配空间.为了提高运行的效率,有对空间进行不同 ...
- SQL日期格式转换(经常用又经常忘记的东西)转载自http://www.cnblogs.com/wangyuelang0526/archive/2012/06/06/2538224.html
Select CONVERT(varchar(100), GETDATE(), 8):14:53:14Select CONVERT(varchar(100), GETDATE(), 9): 06 6 ...
- [原创]Windows下Google V8 javascript引擎编译
项目用到将v8嵌入到C++的情况,公司没时间研究,只有在家研究,编译过程一堆坑.记录一下. 网上百度的都是基于vs2010,或者早版本的v8编译,最新版本应该使用vs2013\vs2015.本文介绍的 ...
- primary key与unique的区别
定义了 UNIQUE 约束的字段中不能包含重复值,可以为一个或多个字段定义 UNIQUE 约束.因此,UNIQUE 即可以在字段级也可以在表级定义, 在UNIQUED 约束的字段上可以包含空值.ORA ...
- CentOS6.5下Mysql数据库的安装与配置
一.mysql简介 说到数据库,我们大多想到的是关系型数据库,比如mysql.oracle.sqlserver等等,这些数据库软件在windows上安装都非常的方便,在Linux上如果要安装数据库,咱 ...
- Python之路第六天,进阶-算法
排序算法 冒泡排序 冒泡排序原理: 原理是临近的数字两两进行比较,按照从小到大或者从大到小的顺序进行交换,这样一趟过去后,最大或最小的数字被交换到了最后一位,然后再从头开始进行两两比较交换,直到倒数第 ...
- pyinstaller打出的EXE包执行时报错“failed to excute ”信息
我的程序是selenium自动化脚本,打包时执行的是 Python pyinstaller -F --onefile -w XXX.py 这样打出的包执行后提示“failed to excute s ...