扩展语法
类目
类目就可以实现在没有类的源代码的条件下为类增加新的方法
扩展NSString的.h头文件
// NSString+GetName.h
// 类目
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSString (GetName)
//@property(nonatomic,strong)NSString *sex;不可以给类别/类目添加属性
- (NSString *)getName;
- (NSInteger)getAge;
@end
NS_ASSUME_NONNULL_END
扩展NSString的.m实现文件
// NSString+GetName.m
// 类目
#import "NSString+GetName.h"
@implementation NSString (GetName)
- (NSString *)getName{
return @"张三";
}
- (NSInteger)getAge{
return 23;
}
@end
使用
//
// ViewController.m
// 类目
#import "ViewController.h"
#import "NSString+GetName.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSstring *str=[[NSString alloc]init];
NSString *name=[str getName];
NSString *age=[str getAge];
NSLog(@"name = %@ age = %d",name,age);
}
@end
延展
为类扩充私有的方法,以及私有的实例变量
延展.h头文件
// User.h
// 延展
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface User : NSObject
@property(nonatomic,strong)NSString *name;
- (void)getName;
@end
NS_ASSUME_NONNULL_END
延展.m实现文件
//
// User.m
// 延展
#import "User.h"
@interface User ()
//延展的属性,私有
@property(nonatomic,assign)NSInteger age;
- (void)setAge;
@end
@implementation User
- (void)setAge{
self.age=12;
}
- (void) getAge{
[self setAge];
NSLog(@"self.age = %ld",(long)self.age);
}
@end
协议,代理
一个类只要遵守了Protocol协议,就相当于拥有了Protocol协议的所有方法声明,类似于java中接口
协议.h头文件
// Person.h
// 协议
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
//协议
@protocol Person<NSObject>
//@required关键字之后声明的方法必选实现
@required
- (void)driveCar;
//@optional关键字之后声明的方法可选实现
@optional
- (void)buyCar;
@end
NS_ASSUME_NONNULL_END
继承协议的.h头文件
// Worker.h
// 协议
#import <Foundation/Foundation.h>
#import "Person.h"
NS_ASSUME_NONNULL_BEGIN
@interface Worker: NSObject<Person>
@property(nonatomic,weak)id<Person> delegate;
@end
NS_ASSUME_NONNULL_END
实现协议的.m文件
// Worker.m
// 协议
#import "Worker.h"
@implementation Worker
- (void)driveCar{
NSLog(@"工作人员开车"):
}
@end
代理.h头文件
//
// Saleman.h
// 协议
#import <Foundation/Foundation.h>
#import "Person.h"
NS_ASSUME_NONNULL_BEGIN
@interface Saleman : NSObject<Person>
@end
NS_ASSUME_NONNULL_END
代理.m实现文件
//
// Saleman.m
// 协议
#import "Saleman.h"
@implementation Saleman
- (void)driveCar{
NSLog(@"销售人员开车");
}
- (void)buyCar{
NSLog(@"销售人员买车");
}
@end
使用
#import "ViewController.h"
#import "Worker.h"
#import "Saleman.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Worker*worker= [[Worker alloc]init];
Saleman*saleman= [[Saleman alloc]init];
//协议是协议 代理是代理
worker.delegate = saleman;//saleman成为了worker的代理
//判断代理是否有此方法
if ([worker.delegate respondsToSelector:@selector(buyCar)]) {
[worker.delegate buyCar];
}
}
@end
KVO
key-value-observer表示当某个属性的值发生变化的时候,通知观察者
编写实体.h头文件
//
// User.h
// KVO
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface User: NSObject
@property(nonatomic,strong)NSString *name;
@property(nonatomic,assign)NSInteger age;
@end
NS_ASSUME_NONNULL_END
实现实体.m文件
// User.h
// KVO
#import "User.h"
@implementation User
@end
使用
// ViewController.m
// KVO
#import "ViewController.h"
#import "Persion.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
User *user= [[User alloc]init];
[user addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
[user addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];
user.name = @"张三";
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
id value = change[NSKeyValueChangeNewKey];
if ([keyPath isEqualToString:@"name"]) {
NSLog(@"name= %@",value);
}else if([keyPath isEqualToString:@"age"]){
NSLog(@"age= %d",value);
}
}
@end
KVC
Key Value Coding(键值编码),是一个基于NSKeyValueCoding非正式协议实现的机制,它可以直接通过key值对对象的属性进行存取操作,而不需通过调用明确的存取方法。这样就可以在运行时动态再访问和修改对象的属性,而不是在编译时确定
实体类.h头文件
//
// Address.h
// KVC
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface Address : NSObject
@property(nonatomic,strong)NSString *city;
@property(nonatomic,strong)NSString *street;
@end
NS_ASSUME_NONNULL_END
实体类.h头文件
//
// //
// Persion.h
// KVC
#import <Foundation/Foundation.h>
#import "Address.h"
NS_ASSUME_NONNULL_BEGIN
@interface User: NSObject
@property(nonatomic,strong)NSString *name;
@property(nonatomic,assign)NSInteger age;
@property(nonatomic,strong)Address *address;
@end
NS_ASSUME_NONNULL_END
使用
// ViewController.m
// KVC
#import "ViewController.h"
#import "User.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//kvc的目的是不通过属性,去赋值和取值
User *user= [[Persion alloc]init];
//利用KVC
//赋值
[user setValue:@"张三" forKey:@"name"];
//取值
// NSLog(@"user.name2 = %@",[user valueForKey:@"name"]);
Address *address = [[Address alloc]init];
// [address setValue:@"wuhu" forKey:@"city"];
// user.address = address;
[persion setValue:address forKey:@"address"];
//多级访问(访问user里面的address里面的city) //多级访问一定是keypath
[user setValue:@"wuhu" forKeyPath:@"address.city"];
// NSLog(@"city = %@",user.address.city);//属性get方法访问
NSLog(@"city01 = %@",[uservalueForKeyPath:@"address.city"]);
}
@end
单例
在整个程序中只有一个实例,并且提供一个类方法供全局调用,在编译时初始化这个类,然后一直保存在内存中,到程序(APP)退出时由系统自动释放这部分内存。
实体类.h头文件
// User.h
// OC单例
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface User: NSObject
+ (User *)shareInstance;
@end
NS_ASSUME_NONNULL_END
实体类.m实现文件
// Persion.m
// OC单例
#import "User.h"
@implementation User
static User *_user;
+(instancetype)allocWithZone:(struct _NSZone *)zone{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (_user == nil) {
_user = [super allocWithZone:zone];
}
});
return _user;
}
+ (User *)shareInstance{
return [[self alloc]init];
}
- (id)copyWithZone:(NSZone *)zone{
return _user;
}
- (id)mutableCopyWithZone:(NSZone*)zone{
return _user;
}
@end
通知
一种消息广播的实现机制,可以在不同对象之间发送通知进而实现通信
1、发送通知
[[NSNotificationCenter defaultCenter] postNotificationName:@"notice" object:nil];
2、向通知中心注册通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(action:) name:@"notice" object:nil];
3、接收通知
action: 是响应接收通知的方法,在收到通知后会调用此方法。name是这个通知的名字。
- (void)action:(NSNotification*)notif
{
NSLog(@"接收到的消息 %@",notif.object);
}
4、销毁通知
在需要销毁的时候,可以根据通知的名字remove掉
-(void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"notice" object:nil];
}
目标动作回调
事件发生时,向指定的对象发送某个特定的信息。这里接收消息的对象是目标,消息的选择器是动作。常用为按钮addTarget属性 ;
// ViewController.m
// 目标动作回调
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//目标动作回调
//目标就是接受事件反馈的对象
//动作:事件反馈所要触发的方法
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self action:@selector(click) forControlEvents:UIControlEventTouchUpInside];
button.frame = CGRectMake(0, 100, 100, 100);
[self.view addSubview:button];
button.backgroundColor = [UIColor redColor];
[button setTitle:@"按钮" forState:UIControlStateNormal];
}
- (void)click{
NSLog(@"我被触发了");
}
@end
委托协议回调
事件发生时,向指定的对象发送某个特定的信息。这里接收消息的对象是目标,消息的选择器是动作。常用为按钮addTarget属性 ;
闹铃协议.h头文件
// Alarm.h
// 委托模式
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@protocol Alarm<NSObject>
- (void)ringing;
@end
NS_ASSUME_NONNULL_END
闹钟遵从闹铃协议.h头文件
//
// Clock.h
// 委托模式
#import <Foundation/Foundation.h>
#import "Alarm.h"
NS_ASSUME_NONNULL_BEGIN
@interface Clock : NSObject<Alarm>
@end
NS_ASSUME_NONNULL_END
闹钟遵从闹铃协议.m实现文件
// Clock.m
// 委托模式
#import "Clock.h"
@implementation Clock
- (void)ringing{
NSLog(@"叮叮叮。。");
}
@end
将闹钟设为人的代理.h头文件
// Person.h
// 委托模式
#import <Foundation/Foundation.h>
#import "Alarm.h"
NS_ASSUME_NONNULL_BEGIN
@interface Person: NSObject
@property(nonatomic,weak)id<Alarm>delegate;
@end
NS_ASSUME_NONNULL_END
使用
// ViewController.m
// 委托模式
#import "ViewController.h"
#import "Person.h"
#import "Clock.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Person*person= [[Personalloc]init];
Clock *clock = [[Clock alloc]init];
person.delegate = clock;
[person.delegate ring];
}
@end
Block回调
子控件TestView.h头文件
// TestView.h
// 回调Block
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
typedef void(^TestBlock)(NSString *str);
@interface TestView : UIView
//视图
@property(nonatomic,strong)void(^changeColor)(NSString *test);
@property(nonatomic,strong)TestBlock testBlock;
//block作为函数的参数
//- (void)userBlock:(void(^)(NSString *str))block;
- (void)userBlock:(TestBlock)testBlock;
@property(nonatomic,strong)void(^changeValueBlock)(void);
@end
NS_ASSUME_NONNULL_END
子控件TestView.m实现文件
// TestView.m
// 回调Block
#import "TestView.h"
@implementation TestView
- (instancetype)init
{
self = [super init];
if (self) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.backgroundColor=[UIColor redColor];
[button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
[button setTitle:@"点我" forState:UIControlStateNormal];
button.titleLabel.font = [UIFont systemFontOfSize:18];
button.frame = CGRectMake(0, 0, 300, 50);
[self addSubview:button];
}
return self;
}
- (void)buttonAction:(UIButton *)sender{
NSLog(@"触发");
self.changeColor(@"函数传过来的参数");
if (self.changeValueBlock) {
self.changeValueBlock();
}
}
//- (void)userBlock:(void(^)(NSString *str))block{
// self.changeColor = block;
//}
- (void)userBlock:(TestBlock)testBlock{
self.changeColor = testBlock;
}
@end
使用
// ViewController.m
// 回调Block
#import "ViewController.h"
#import "TestView.h"
#import "FirstViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//block
/*
代码块Block是苹果在iOS4开始引入的对C语言的扩展,用来实现匿名函数的特性,Block是一种特殊的数据类型,其可以正常定义变量、作为参数、作为返回值;Block被广泛运用在回调。
注: Block的声明与赋值只是保存了一段代码段,必须调用才能执行内部代码.
*/
TestView *view = [[TestView alloc]init];
view.frame = CGRectMake(self.view.frame.size.width/2.0 - 150, 300, 300, 50);
[self.view addSubview: view];
view.changeColor = ^(NSString * _Nonnull test) {
NSLog(@"test = %@",test);
};
// [view userBlock:^(NSString * _Nonnull str) {
// NSLog(@"str = %@",str);
// self.view.backgroundColor = [UIColor greenColor];
// }];
[view userBlock:^(NSString * _Nonnull str) {
NSLog(@"str = %@",str);
self.view.backgroundColor = [UIColor greenColor];
}];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.backgroundColor=[UIColor redColor];
[button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
[button setTitle:@"按钮1" forState:UIControlStateNormal];
button.titleLabel.font = [UIFont systemFontOfSize:18];
button.frame = CGRectMake(0, 100, 300, 50);
[self.view addSubview:button];
}
- (void)buttonAction:(UIButton *)sender{
NSLog(@"按钮1事件");
// self.view.backgroundColor = [UIColor yellowColor];
FirstViewController *firstViewControlelr = [[FirstViewController alloc]init];
[self presentViewController:firstViewControlelr animated:YES completion:^{
}];
}
@end