您的位置:首页 > 移动开发 > IOS开发

iOS 分类的基本使用(更改frame)以及全局变量.pch的使用

2015-08-25 23:01 453 查看

iOS分类基础以及基本应用

Objective-C提供了一个非常灵活的类(Class)扩展机制-类别(Category)。

类别用于对一个已经存在的类添加方法(Methods)。你只需要知道这个类的公开接口,

不需要知道类的源代码。需要注意的是,类别不能为已存在的类添加实例变量(Instance Variables)。

注意几点:

1.现有类的类名位于 @interface之后

2.括号中是类别的名称(只要名称唯一,可以添加任意多的类别)

3.类别没有实例变量部分

分类的作用:

(1)将类的实现分散到多个不同文件或多个不同框架中。

(2)创建对私有方法的前向引用。

(3)向对象添加非正式协议。

类别的局限性

有两方面局限性:

(1)无法向类中添加新的实例变量,类别没有位置容纳实例变量。

(2)名称冲突,即当类别中的方法与原始类方法名称冲突时,类别具有更高的优先级。类别方法将完全取代初始方法从而无法再使用初始方法。

无法添加实例变量的局限可以使用字典对象解决.

What’s more?

创建一个NSObject的类别称为“创建一个非正式协议”。因为,NSObject是顶级父类,在NSObject中添加了该方法,也就是说通过继承关系,所有的类中都有该方法。

正式协议是通过protocol指定的一些列方法的声明,然后由实现该协议的类自己去实现这些方法。

而非正式协议是通过向NSObject中添加一个类别来实现,然后子类去继承NSObject。其实都差不多。

不过,非正式协议已经渐渐被正式协议取代,正式协议最大的优点就是可以使用泛型约束

下面就具体如何使用类别举例:

假设一个Teacher类,在.h中暴露一个teach(讲课)的方法,实现文件.m中又定义了一个preteach(备课)的私有方法,一般情况下无法访问到这个没有暴露在接口文件的私有方法。下面我用分类对它进行访问。

新建类Teacher

#import <Foundation/Foundation.h>
@interface Teacher : NSObject
- (void)teach;
@end


在实现文件中实现方法:

#import "Teacher.h"

@implementation Teacher

- (void)teach{
NSLog(@"方法--老师讲课");
}

- (void)preteach{
NSLog(@"方法--老师备课");
}//该方法没有在接口中定义,为私有的

@end


接下来,新建分类






可以看到xcode左边列表中:



分类文件名的形式正如上图所见,当然这是xcode帮我们加的,有利于编辑,并非OC语法规定是这种形式。

Teacher+Extension.h中:

@interface Teacher (Extension)
- (void)preteach;
@end


Teacher+Extension.m中

@implementation Teacher (Extension)
@end


这时在.m文件中会出现如下警告(如果没有出现警告,可用cmd+B编译一下):



出现这个警告的原因应该是Apple建议要在.m文件中实现接口中定义的方法。不过我这里就不实现了,因为我是为了访问之前的私有方法,当在分类中找不到调用的方法时,会向上即父类寻找调用的方法,这时就给我们访问Teacher类中的私有方法的契机。

接下来,在ViewController.m中,导入 #import “Teacher+Extension.h”

- (void)viewDidLoad {
[super viewDidLoad];
Teacher *t = [[Teacher alloc] init];
[t teach];
[t preteach];
}


现在cmd+R运行一下,此时Teacher中的私有方法 preteach得意访问了<( ̄︶ ̄)> 

iOS中的应用举例

一般情况下,直接更改控件或者视图的位置是不行的,如果有n个视图的位置需要改,如何用最简单最直接的方法?

let’s see…

首先,在ViewController中初始化一个UILabel,并添加到当前视图中。并尝试修改它的frame:

UILabel *label = [[UILabel alloc] init];
label.backgroundColor = [UIColor purpleColor];
label.frame = CGRectMake(100, 100, 100, 30);
label.frame.size.width = 300;
[self.view addSubview:label];


这时你会得到编译器的警告:



由于只读属性的问题,我们无法直接修改,如何解决?

解决方法一:

CGRect *rect = CGRectMake(100,100,200,30);

label.frame = rect;

运行一下,观察目前的位置:



这个通过间接更换一个frame。但是如果n个要修改,岂不是会让人die of coding?

解决方法二:

使用分类的方法

新建分类



在UIView+Extension.h中

@interface UIView (Extension)
@property (nonatomic,assign) CGFloat width;
@property (nonatomic,assign) CGFloat height;
@property (nonatomic,assign) CGFloat x;
@property (nonatomic,assign) CGFloat y;
@end


在UIView+Extension.m中,为属性设置getter,setter方法(实质是重写了原属性的getter,setter方法)

@implementation UIView (Extension)

- (void)setWidth:(CGFloat)width{
CGRect frame = self.frame;
frame.size.width = width;
self.frame = frame;
}

- (CGFloat)width{
CGRect frame = self.frame;
return frame.size.width;
}

-(void)setHeight:(CGFloat)height{
CGRect frame = self.frame;
frame.size.height = height;
self.frame = frame;
}

- (CGFloat)height{
CGRect frame = self.frame;
return frame.size.height;
}

- (void)setX:(CGFloat)x{
CGRect frame = self.frame;
frame.origin.x = x;
self.frame = frame;
}

- (CGFloat)x{
CGRect frame = self.frame;
return frame.origin.x;
}

- (void)setY:(CGFloat)y{
CGRect frame = self.frame;
frame.origin.y = y;
self.frame = frame;
}

- (CGFloat)y{
CGRect frame = self.frame;
return frame.origin.y;
}
@end


这样,你就可以直接随意更改frame的大小位置啦~

在ViewController中

先导入:#import "UIView+Extension.h"
在实例化好的Label下:
label.width = 300;
label.height = 50;
label.x = 10;
label.y = 10;




但是这样还存在一个问题,如果在n个视图控制器中都要调整frame,是不是意味着要#import n次呢?这样效率会非常低,为了解决之,可以使用.pch

.pch 概述:.pch表示”precompiled header”,这是一个你工程要用到的来自于外部框架的头文件列表,在里面往往写一些经常使用的框架头文件或者一些宏定义的URL地址。xcode将编译这些头到文件,这将减少开发时间、代码维护时间。

下面是实用步骤:

cmd+N添加新文件:



在新建的.pch文件中,加入
#import "UIView+Extension.h"


然后点击单击项目,在Building Settings中,levels栏目中,搜索”header”,将Pleaserecompile Prefix Header选项设置为YES



接着在Prefix Header 内容中双击,输入一下内容:



/fenlei 是该项目的名字,/Globe.pch 是刚刚新建的.pch文件

这样,系统编译每个.m文件前,都会先imort你写入的文件头

ps:刚入门iOS不久,若有错误之处,还请多多指教,吾必虚心接受并思之改之( ̄▽ ̄)~*
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息