add flying commit
This commit is contained in:
@@ -48,5 +48,10 @@
|
||||
+(CGFloat)getSpaceLabelHeight:(NSString*)str withFont:(UIFont*)font maxSize:(CGSize)maxSize;
|
||||
+(void)setLabelSpace:(UILabel*)label withValue:(NSString*)str withFont:(UIFont*)font;
|
||||
|
||||
/**
|
||||
是否是手机号
|
||||
*/
|
||||
+(BOOL)isPhoneNumber:(NSString*)mobileNumber;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@@ -144,4 +144,34 @@
|
||||
label.attributedText = attributeStr;
|
||||
|
||||
}
|
||||
|
||||
+(BOOL)isPhoneNumber:(NSString*)mobileNumber{
|
||||
|
||||
if (mobileNumber.length != 11)
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
/** * 手机号码: * 13[0-9], 14[5,7], 15[0, 1, 2, 3, 5, 6, 7, 8, 9], 17[6, 7, 8], 18[0-9], 170[0-9] * 移动号段: 134,135,136,137,138,139,150,151,152,157,158,159,182,183,184,187,188,147,178,1705 * 联通号段: 130,131,132,155,156,185,186,145,176,1709 * 电信号段: 133,153,180,181,189,177,1700 */
|
||||
NSString *MOBILE = @"^1(3[0-9]|4[57]|5[0-35-9]|8[0-9]|7[0678])\\d{8}$";
|
||||
/** * 中国移动:China Mobile * 134,135,136,137,138,139,150,151,152,157,158,159,182,183,184,187,188,147,178,1705 */
|
||||
NSString *CM = @"(^1(3[4-9]|4[7]|5[0-27-9]|7[8]|8[2-478])\\d{8}$)|(^1705\\d{7}$)";
|
||||
/** * 中国联通:China Unicom * 130,131,132,155,156,185,186,145,176,1709 */
|
||||
NSString *CU = @"(^1(3[0-2]|4[5]|5[56]|7[6]|8[56])\\d{8}$)|(^1709\\d{7}$)"; /** * 中国电信:China Telecom * 133,153,180,181,189,177,1700 */
|
||||
NSString *CT = @"(^1(33|53|77|8[019])\\d{8}$)|(^1700\\d{7}$)";
|
||||
/** 25 * 大陆地区固话及小灵通 26 * 区号:010,020,021,022,023,024,025,027,028,029 27 * 号码:七位或八位 28 */ //
|
||||
// NSString * PHS = @"^(0[0-9]{2})\\d{8}$|^(0[0-9]{3}(\\d{7,8}))$";
|
||||
NSPredicate *regextestmobile = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", MOBILE];
|
||||
NSPredicate *regextestcm = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CM];
|
||||
NSPredicate *regextestcu = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CU];
|
||||
NSPredicate *regextestct = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CT];
|
||||
if (([regextestmobile evaluateWithObject:mobileNumber] == YES) || ([regextestcm evaluateWithObject:mobileNumber] == YES) || ([regextestct evaluateWithObject:mobileNumber] == YES) || ([regextestcu evaluateWithObject:mobileNumber] == YES)) {
|
||||
return YES;
|
||||
|
||||
} else {
|
||||
return NO;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -44,11 +44,10 @@
|
||||
content.attachments = @[attachAudio];
|
||||
|
||||
//延迟通知 第一个参数是重复的时间间隔,最小60s,第二个参数是是否重复。
|
||||
UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:60 repeats:NO];
|
||||
UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:timeInterval repeats:NO];
|
||||
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:trigger];
|
||||
[center addNotificationRequest:request withCompletionHandler:^(NSError *_Nullable error) {
|
||||
GILog(@"成功添加推送");
|
||||
|
||||
}];
|
||||
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// LXDanMuManager.h
|
||||
// LXAnimationTest
|
||||
//
|
||||
// Created by lianxiang on 2018/8/14.
|
||||
// Copyright © 2018年 com.giga.ios. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
@interface LXDanMuManager : NSObject
|
||||
@property (nonatomic,strong) NSArray *trackSpeedArray;
|
||||
@property (nonatomic,assign) float centerY;//所有轨道中心点
|
||||
@property (nonatomic,assign) float trackWidth;
|
||||
@property (nonatomic,strong) NSTimer *timer;
|
||||
@property (nonatomic,strong) UIView *superView;
|
||||
@property (nonatomic,strong) NSMutableArray *trackArray;
|
||||
@property (nonatomic,strong) UIView *baseView;
|
||||
|
||||
+(LXDanMuManager *)shareInstance;
|
||||
-(void)createDanmuWithTrackSpeedArray:(NSArray *)trackSpeedArray centerY:(float)centerY trackWidth:(float)trackWidth showInView:(UIView *)inView;
|
||||
/**
|
||||
插入一条弹幕,可以插入任意继承UIView的对象
|
||||
|
||||
@param customView 自定义的view(注意,最高不能超过轨道的高,否则会出问题)
|
||||
@param trackIndex 插入弹幕的轨道(为-1则代表自动寻找最不拥挤的轨道插入)
|
||||
*/
|
||||
-(void)appendDanMuWithCustomView:(UIView *)customView toTrackIndex:(NSInteger)trackIndex;
|
||||
-(void)start;
|
||||
-(void)pause;
|
||||
-(void)stop;
|
||||
-(void)destory;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,145 @@
|
||||
//
|
||||
// LXDanMuManager.m
|
||||
// LXAnimationTest
|
||||
//
|
||||
// Created by lianxiang on 2018/8/14.
|
||||
// Copyright © 2018年 com.giga.ios. All rights reserved.
|
||||
//
|
||||
|
||||
#import "LXDanMuManager.h"
|
||||
#import "LXDanMuTrackView.h"
|
||||
|
||||
@implementation LXDanMuManager
|
||||
|
||||
+ (LXDanMuManager *)shareInstance{
|
||||
static LXDanMuManager *managerInstance = nil;
|
||||
static dispatch_once_t once;
|
||||
dispatch_once(&once, ^{
|
||||
managerInstance = [[self alloc] init];
|
||||
});
|
||||
return managerInstance;
|
||||
}
|
||||
|
||||
- (void)createDanmuWithTrackSpeedArray:(NSArray *)trackSpeedArray centerY:(float)centerY trackWidth:(float)trackWidth showInView:(UIView *)inView{
|
||||
_superView = inView;
|
||||
_trackSpeedArray = trackSpeedArray;
|
||||
_centerY = centerY;
|
||||
_trackWidth = trackWidth;
|
||||
_trackArray = [[NSMutableArray alloc] init];
|
||||
[self initUI];
|
||||
}
|
||||
|
||||
-(void)initUI{
|
||||
_baseView = [[UIView alloc] initWithFrame:CGRectMake(0, 0,_trackWidth, 0)];
|
||||
_baseView.userInteractionEnabled = NO;
|
||||
[_superView addSubview:_baseView];
|
||||
|
||||
for (int i = 0; i<_trackSpeedArray.count; i++) {
|
||||
|
||||
LXDanMuTrackView *trackView = [[LXDanMuTrackView alloc] initWithFrame:CGRectMake(0, (TRACK_HEIGHT + TRACK_VERTICAL_PADDING) * i, _baseView.frame.size.width, TRACK_HEIGHT)];
|
||||
[_baseView addSubview:trackView];
|
||||
[_trackArray addObject:trackView];
|
||||
if (_trackSpeedArray.count - 1 == i) {
|
||||
_baseView.frame = CGRectMake(_baseView.frame.origin.x, _baseView.frame.origin.y, _baseView.frame.size.width,CGRectGetMaxY(trackView.frame));
|
||||
_baseView.center = CGPointMake(_baseView.center.x, _centerY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-(void)start{
|
||||
|
||||
if (_timer) {
|
||||
return;
|
||||
}
|
||||
_timer = [NSTimer timerWithTimeInterval:0.01 target:self selector:@selector(startAction) userInfo:nil repeats:YES];
|
||||
[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
|
||||
|
||||
}
|
||||
|
||||
- (void)pause{
|
||||
[_timer invalidate];
|
||||
_timer = nil;
|
||||
}
|
||||
|
||||
- (void)stop{
|
||||
|
||||
[_timer invalidate];
|
||||
_timer = nil;
|
||||
for (LXDanMuTrackView *trackView in _trackArray) {
|
||||
[trackView cleanTrack];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)destory{
|
||||
|
||||
[_timer invalidate];
|
||||
_timer = nil;
|
||||
for (LXDanMuTrackView * trackView in _trackArray) {
|
||||
[trackView cleanTrack];
|
||||
[trackView removeFromSuperview];
|
||||
}
|
||||
[_trackArray removeAllObjects];
|
||||
[_baseView removeFromSuperview];
|
||||
_trackSpeedArray = nil;
|
||||
_superView = nil;
|
||||
_baseView = nil;
|
||||
_trackArray = nil;
|
||||
|
||||
}
|
||||
|
||||
-(void)startAction{
|
||||
|
||||
for (int i = 0; i < _trackArray.count; i++) {
|
||||
//执行轨道定时器方法
|
||||
LXDanMuTrackView *trackView = _trackArray[i];
|
||||
[trackView moveViewWithSpeed:[_trackSpeedArray[i] floatValue]];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
-(UIView *)baseView{
|
||||
if (!_baseView) {
|
||||
_baseView = [[UIView alloc] initWithFrame:CGRectMake(0, 0,_trackWidth, 0)];
|
||||
|
||||
}
|
||||
return _baseView;
|
||||
}
|
||||
|
||||
//自定义的view(注意,最高不能超过轨道的高,会出问题)
|
||||
- (void)appendDanMuWithCustomView:(UIView *)customView toTrackIndex:(NSInteger)trackIndex
|
||||
{
|
||||
//trackIndex 插入弹幕的轨道(为-1则代表自动寻找最不拥挤的轨道插入)
|
||||
NSInteger realTrackIndex = trackIndex;
|
||||
if (realTrackIndex == -1) {
|
||||
realTrackIndex = [self findTheMinTotalWidthTrack];
|
||||
}
|
||||
LXDanMuTrackView *trackView = _trackArray[realTrackIndex];
|
||||
[trackView appendWithCustomView:customView];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
找到最短右侧出屏幕和等待数组总长度最短的轨道序号
|
||||
|
||||
@return 轨道的序号
|
||||
*/
|
||||
|
||||
- (int)findTheMinTotalWidthTrack
|
||||
{
|
||||
LXDanMuTrackView *firstTrackView = _trackArray[0];
|
||||
int minWidthIndex = 0;
|
||||
float minWidth = [firstTrackView rightOutScreenWidth];
|
||||
for (int i = 0; i<_trackArray.count; i++)
|
||||
{
|
||||
LXDanMuTrackView *trackView = _trackArray[i];
|
||||
float trackRightOutScreenWidth = [trackView rightOutScreenWidth];
|
||||
if (trackRightOutScreenWidth < minWidth)
|
||||
{
|
||||
minWidth = trackRightOutScreenWidth;
|
||||
minWidthIndex = i;
|
||||
}
|
||||
}
|
||||
return minWidthIndex;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// LXDanMuManagerConfig.h
|
||||
// LXAnimationTest
|
||||
//
|
||||
// Created by lianxiang on 2018/8/14.
|
||||
// Copyright © 2018年 com.giga.ios. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef LXDanMuManagerConfig_h
|
||||
#define LXDanMuManagerConfig_h
|
||||
|
||||
//轨道中弹幕的最小间距
|
||||
#define TRACK_HORIZONTAL_PADDING 10
|
||||
//轨道与轨道的纵向间距
|
||||
#define TRACK_VERTICAL_PADDING 10
|
||||
//轨道的高度(轨道上的View不能超过此高度)
|
||||
#define TRACK_HEIGHT 60
|
||||
|
||||
#endif /* LXDanMuManagerConfig_h */
|
||||
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// LXDanMuTrackView.h
|
||||
// LXAnimationTest
|
||||
//
|
||||
// Created by lianxiang on 2018/8/14.
|
||||
// Copyright © 2018年 com.giga.ios. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "LXDanMuManagerConfig.h"
|
||||
|
||||
@interface LXDanMuTrackView : UIView
|
||||
|
||||
/**
|
||||
等待出现到屏幕中的弹幕view数组
|
||||
*/
|
||||
@property (nonatomic,strong) NSMutableArray *waitShowArray;
|
||||
|
||||
/**
|
||||
正在展示的弹幕view数组
|
||||
*/
|
||||
@property (nonatomic,strong) NSMutableArray *showingArray;
|
||||
/**
|
||||
向轨道中插入一条自定义的view
|
||||
|
||||
@param view 自定义的view,高度不可超过轨道的高,否则出问题
|
||||
*/
|
||||
- (void)appendWithCustomView:(UIView *)view;
|
||||
|
||||
/**
|
||||
当前轨道右侧出屏幕的距离+等待出现到屏幕中的弹幕view的总长度和
|
||||
@return 等待弹幕+右侧出屏幕弹幕的和
|
||||
*/
|
||||
- (float)rightOutScreenWidth;
|
||||
/**
|
||||
清理轨道,移除所有弹幕
|
||||
*/
|
||||
- (void)cleanTrack;
|
||||
/**
|
||||
根据速度移动轨道中所有弹幕的位置
|
||||
|
||||
@param speed 每0.01秒弹幕向左移动的距离
|
||||
*/
|
||||
- (void)moveViewWithSpeed:(float)speed;
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,123 @@
|
||||
//
|
||||
// LXDanMuTrackView.m
|
||||
// LXAnimationTest
|
||||
//
|
||||
// Created by lianxiang on 2018/8/14.
|
||||
// Copyright © 2018年 com.giga.ios. All rights reserved.
|
||||
//
|
||||
|
||||
#import "LXDanMuTrackView.h"
|
||||
|
||||
@implementation LXDanMuTrackView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame{
|
||||
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self dataConfig];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)dataConfig{
|
||||
|
||||
_showingArray = [[NSMutableArray alloc] init];
|
||||
_waitShowArray = [[NSMutableArray alloc] init];
|
||||
|
||||
}
|
||||
|
||||
- (void)appendWithCustomView:(UIView *)view{
|
||||
|
||||
view.frame = CGRectMake(self.frame.size.width,view.frame.origin.y, view.frame.size.width,view.frame.size.height);
|
||||
view.center = CGPointMake(view.center.x, TRACK_HEIGHT/2);
|
||||
if (_showingArray.count) {
|
||||
UIView *lastView = [_showingArray lastObject];
|
||||
//最右侧的那条弹幕还没有完全出现在屏幕中
|
||||
if (CGRectGetMaxX(lastView.frame) + TRACK_HORIZONTAL_PADDING > self.frame.size.width || _waitShowArray.count) {
|
||||
//把这条弹幕加到等待数组中
|
||||
[_waitShowArray addObject:view];
|
||||
}else{
|
||||
//加入轨道
|
||||
[self addSubview:view];
|
||||
//加入展示数组
|
||||
[_showingArray addObject:view];
|
||||
|
||||
}
|
||||
}else{
|
||||
|
||||
[self addSubview:view];
|
||||
[_showingArray addObject:view];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)moveViewWithSpeed:(float)speed{
|
||||
//正在展示的弹幕自减一次
|
||||
for (UIView *view in _showingArray) {
|
||||
view.frame = CGRectMake(view.frame.origin.x - speed, view.frame.origin.y, view.frame.size.width, view.frame.size.height);
|
||||
|
||||
}
|
||||
//正在展示的弹幕
|
||||
if (_showingArray.count){
|
||||
UIView *firstView = [_showingArray firstObject];
|
||||
UIView *lastView = [_showingArray lastObject];
|
||||
|
||||
if (CGRectGetMaxX(firstView.frame) < 0) {
|
||||
//已移除屏幕 remove
|
||||
[firstView removeFromSuperview];
|
||||
[_showingArray removeObjectAtIndex:0];
|
||||
|
||||
}
|
||||
if (_waitShowArray.count) {
|
||||
//最右侧的view 已经完全出现
|
||||
if (CGRectGetMaxX(lastView.frame) + TRACK_HORIZONTAL_PADDING <= self.frame.size.width) {
|
||||
//转移数组
|
||||
[_showingArray addObject:[_waitShowArray firstObject]];
|
||||
[_waitShowArray removeObjectAtIndex:0];
|
||||
[self addSubview:[_showingArray lastObject]];
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
- (float)rightOutScreenWidth
|
||||
{
|
||||
float outScreenWidth = 0.0;
|
||||
//如果等待数组中有值
|
||||
if (_waitShowArray.count)
|
||||
{
|
||||
//先遍历所有等待数组中的view,累加长度和间距
|
||||
for (UIView *view in _waitShowArray)
|
||||
{
|
||||
outScreenWidth += view.frame.size.width + TRACK_HORIZONTAL_PADDING;
|
||||
}
|
||||
}
|
||||
|
||||
//如果展示数组中有值
|
||||
if (_showingArray.count)
|
||||
{
|
||||
//拿出最右侧的view
|
||||
UIView *lastView = [_showingArray lastObject];
|
||||
//算出出屏宽
|
||||
float rightOutWidth = CGRectGetMaxX(lastView.frame) - self.frame.size.width;
|
||||
if (rightOutWidth < 0)
|
||||
{
|
||||
rightOutWidth = 0;
|
||||
}
|
||||
outScreenWidth += rightOutWidth;
|
||||
}
|
||||
|
||||
return outScreenWidth;
|
||||
}
|
||||
|
||||
//清理轨道
|
||||
- (void)cleanTrack
|
||||
{
|
||||
for (UIView *view in _showingArray)
|
||||
{
|
||||
[view removeFromSuperview];
|
||||
}
|
||||
[_showingArray removeAllObjects];
|
||||
[_waitShowArray removeAllObjects];
|
||||
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// GiGaSocketRocketUtility.h
|
||||
// LXAnimationTest
|
||||
//
|
||||
// Created by lianxiang on 2018/8/17.
|
||||
// Copyright © 2018年 com.giga.ios. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SocketRocket.h"
|
||||
extern NSString * const kNeedPayOrderNote;
|
||||
extern NSString * const kWebSocketDidOpenNote;
|
||||
extern NSString * const kWebSocketDidCloseNote;
|
||||
extern NSString * const kWebSocketdidReceiveMessageNote;
|
||||
|
||||
@interface GiGaSocketRocketUtility : NSObject
|
||||
// 获取连接状态
|
||||
@property (nonatomic,assign,readonly) SRReadyState socketReadyState;
|
||||
|
||||
+ (GiGaSocketRocketUtility *)shareInstance;
|
||||
-(void)srWebSocketOpenWithURLString:(NSString *)urlString;//开启连接
|
||||
-(void)srWebSocketClose;//关闭连接
|
||||
- (void)sendData:(id)data;//发送数据
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,248 @@
|
||||
//
|
||||
// GiGaSocketRocketUtility.m
|
||||
// LXAnimationTest
|
||||
//
|
||||
// Created by lianxiang on 2018/8/17.
|
||||
// Copyright © 2018年 com.giga.ios. All rights reserved.
|
||||
//
|
||||
|
||||
#import "GiGaSocketRocketUtility.h"
|
||||
|
||||
#define dispatch_main_async_safe(block)\
|
||||
if ([NSThread isMainThread]) {\
|
||||
block();\
|
||||
} else {\
|
||||
dispatch_async(dispatch_get_main_queue(), block);\
|
||||
}
|
||||
|
||||
NSString * const kNeedPayOrderNote = @"kNeedPayOrderNote";//发送的通知名
|
||||
NSString * const kWebSocketDidOpenNote = @"kWebSocketdidReceiveMessageNote";
|
||||
NSString * const kWebSocketDidCloseNote = @"kWebSocketDidCloseNote";
|
||||
NSString * const kWebSocketdidReceiveMessageNote = @"kWebSocketdidReceiveMessageNote";
|
||||
|
||||
@interface GiGaSocketRocketUtility()<SRWebSocketDelegate>
|
||||
{
|
||||
int _index;
|
||||
NSTimer *heartBeat;
|
||||
NSTimeInterval reConnectTime;
|
||||
}
|
||||
|
||||
@property (nonatomic,strong) SRWebSocket *socket;
|
||||
@property (nonatomic,copy) NSString *urlString;
|
||||
|
||||
@end
|
||||
|
||||
@implementation GiGaSocketRocketUtility
|
||||
|
||||
+(GiGaSocketRocketUtility *)shareInstance{
|
||||
|
||||
static GiGaSocketRocketUtility *instance = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
instance = [[self alloc] init];
|
||||
|
||||
});
|
||||
return instance;
|
||||
}
|
||||
//开启链接
|
||||
-(void)srWebSocketOpenWithURLString:(NSString *)url{
|
||||
|
||||
if (!self.socket) {
|
||||
return;
|
||||
}
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
self.urlString = url;
|
||||
self.socket = [[SRWebSocket alloc] initWithURLRequest: [NSURLRequest requestWithURL:[NSURL URLWithString:url]]] ;
|
||||
NSLog(@"请求的websocket地址:%@",self.socket.url.absoluteString);
|
||||
self.socket.delegate = self;
|
||||
[self.socket open];
|
||||
|
||||
}
|
||||
//关闭连接
|
||||
|
||||
-(void)srWebSocketClose{
|
||||
|
||||
if (self.socket) {
|
||||
[self.socket close];
|
||||
self.socket = nil;
|
||||
[self removeHeartBeat];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//移除心跳
|
||||
-(void)removeHeartBeat{
|
||||
|
||||
dispatch_main_async_safe(^{
|
||||
if (self->heartBeat) {
|
||||
if ([self->heartBeat respondsToSelector:@selector(isValid)]) {
|
||||
if ([self->heartBeat isValid]) {
|
||||
[self->heartBeat invalidate];
|
||||
self->heartBeat = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
//初始化心跳
|
||||
- (void)initHeartBeat
|
||||
{
|
||||
dispatch_main_async_safe(^{
|
||||
[self removeHeartBeat];
|
||||
//心跳设置为3分钟,NAT超时一般为5分钟
|
||||
self->heartBeat = [NSTimer timerWithTimeInterval:3 target:self selector:@selector(sentheart) userInfo:nil repeats:YES];
|
||||
//和服务端约定好发送什么作为心跳标识,尽可能的减小心跳包大小
|
||||
[[NSRunLoop currentRunLoop] addTimer:self->heartBeat forMode:NSRunLoopCommonModes];
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
-(void)sentheart{
|
||||
//发送心跳 和后台可以约定发送什么内容 一般可以调用ping 这里发送data
|
||||
[self sendData:@"heart"];
|
||||
|
||||
}
|
||||
|
||||
#define WeakSelf(ws) __weak __typeof(&*self)weakSelf = self
|
||||
|
||||
- (void)sendData:(id)data {
|
||||
|
||||
NSLog(@"socketSendData --------------- %@",data);
|
||||
WeakSelf(ws);
|
||||
dispatch_queue_t queue = dispatch_queue_create("giga", NULL);
|
||||
|
||||
dispatch_async(queue, ^{
|
||||
if (weakSelf.socket != nil) {
|
||||
// 只有 SR_OPEN 开启状态才能调 send 方法啊,不然要崩
|
||||
if (weakSelf.socket.readyState == SR_OPEN) {
|
||||
[weakSelf.socket send:data]; // 发送数据
|
||||
|
||||
} else if (weakSelf.socket.readyState == SR_CONNECTING) {
|
||||
NSLog(@"正在连接中,重连后其他方法会去自动同步数据");
|
||||
// 每隔2秒检测一次 socket.readyState 状态,检测 10 次左右
|
||||
// 只要有一次状态是 SR_OPEN 的就调用 [ws.socket send:data] 发送数据
|
||||
// 如果 10 次都还是没连上的,那这个发送请求就丢失了,这种情况是服务器的问题了,小概率的
|
||||
|
||||
//重连
|
||||
[self reConnect];
|
||||
|
||||
} else if (weakSelf.socket.readyState == SR_CLOSING || weakSelf.socket.readyState == SR_CLOSED) {
|
||||
// websocket 断开了,调用 reConnect 方法重连
|
||||
NSLog(@"重连");
|
||||
[self reConnect];
|
||||
|
||||
}
|
||||
} else {
|
||||
|
||||
NSLog(@"没网络,发送失败,一旦断网 socket 会被我设置 nil 的");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//pingPong
|
||||
- (void)ping{
|
||||
|
||||
if (self.socket.readyState == SR_OPEN) {
|
||||
[self.socket sendPing:nil];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - socket delegate
|
||||
|
||||
- (void)webSocketDidOpen:(SRWebSocket *)webSocket{
|
||||
//每次正常连接的时候清零重连时间
|
||||
reConnectTime = 0;
|
||||
//开启心跳
|
||||
[self initHeartBeat];
|
||||
if (webSocket == self.socket) {
|
||||
NSLog(@"************************** socket 连接成功************************** ");
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kWebSocketDidOpenNote object:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error
|
||||
{
|
||||
if (webSocket == self.socket) {
|
||||
NSLog(@"************************** socket 连接失败************************** ");
|
||||
NSLog(@"err:%@",error);
|
||||
|
||||
_socket = nil;
|
||||
//连接失败就重连
|
||||
[self reConnect];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean{
|
||||
|
||||
if (webSocket == self.socket) {
|
||||
NSLog(@"************************** socket连接断开************************** ");
|
||||
NSLog(@"被关闭连接,code:%ld,reason:%@,wasClean:%d",(long)code,reason,wasClean);
|
||||
[self srWebSocketClose];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kWebSocketDidCloseNote object:nil];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*该函数是接收服务器发送的pong消息,其中最后一个是接受pong消息的,
|
||||
在这里就要提一下心跳包,一般情况下建立长连接都会建立一个心跳包,
|
||||
用于每隔一段时间通知一次服务端,客户端还是在线,这个心跳包其实就是一个ping消息,
|
||||
我的理解就是建立一个定时器,每隔十秒或者十五秒向服务端发送一个ping消息,这个消息可是是空的
|
||||
*/
|
||||
|
||||
-(void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload{
|
||||
|
||||
NSString *reply = [[NSString alloc] initWithData:pongPayload encoding:NSUTF8StringEncoding];
|
||||
NSLog(@"pongPayload===%@",reply);
|
||||
|
||||
}
|
||||
|
||||
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message{
|
||||
|
||||
if (webSocket == self.socket) {
|
||||
NSLog(@"************************** socket收到数据了************************** ");
|
||||
NSLog(@"我这后台约定的 message 是 json 格式数据收到数据,就按格式解析吧,然后把数据发给调用层");
|
||||
NSLog(@"message:%@",message);
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kWebSocketdidReceiveMessageNote object:message];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark methods
|
||||
//重连机制
|
||||
-(void)reConnect{
|
||||
[self srWebSocketClose];
|
||||
//超过一分钟就不再重连 所以只会重连5次 2^5 = 64
|
||||
if (reConnectTime > 64) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(reConnectTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
self.socket = nil;
|
||||
[self srWebSocketOpenWithURLString:self.urlString];
|
||||
NSLog(@"重连");
|
||||
});
|
||||
//重连时间2的指数级增长
|
||||
if (reConnectTime ==0 ) {
|
||||
reConnectTime = 2;
|
||||
|
||||
}else{
|
||||
reConnectTime *=2;
|
||||
}
|
||||
}
|
||||
|
||||
- (SRReadyState)socketReadyState{
|
||||
return self.socket.readyState;
|
||||
}
|
||||
|
||||
-(void)dealloc{
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user