Runtime 到底是个什么鬼?

Runtime是Objective-C中底层的一套C语言API,是一个将C语言转化为面向对象语言的拓展。Runtime的一切都围绕两个中心:类的动态配置消息传递

能干啥?

  • 动态的在内存中创建一个类
  • 给类增加一个属性
  • 给类增加一个协议实现
  • 给类增加一个方法实现IMP
  • 遍历一个类的所有成员变量、属性和方法等
  • 拦截系统自带的方法调用(Method Swizzling黑魔法)
  • 将某些OC代码转化为Runtime代码,探究底层。如block的实现原理
  • 实现给分类增加属性
  • 实现NSCoding的自动归档和接档
  • 实现字典的模型和自动转换

1、iOS 11之前的导航栏的高度是64px(状态条+导航栏),iOS11之后如果设置了prefersLargeTitles = YES(默认NO)则为96pt。所以一般不用管。

2、在iOS 11上运行tableView向下偏移64px或者20px,因为iOS 11废弃了automaticallyAdjustsScrollViewInsets,而是给UIScrollView增加了contentInsetAdjustmentBehavior属性。避免这个坑的方法是要判断

3、tableView的sectionHeader、sectionFooter高度与设置不符,因为tableView的estimatedRowHeight、estimatedSectionHeaderHeight、 estimatedSectionFooterHeight三个高度估算属性由默认的0变成了UITableViewAutomaticDimension。最简单的方法就是直接设置为0。

4、iPhone X状态条由20px变成了44px,UITabBar由49px变成了83px。设置布局时y直接写成64的就要根据机型设置。可以设置宏

#define Device_Is_iPhoneX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125, 2436), [[UIScreen mainScreen] currentMode].size) : NO),

推送模块,推送消息存储

H5 的webView 跳转 与原生交互。

图片压缩缓存。 发表话题。

图片

抽奖功能模块源码
产品出发点
1、通过动态抽奖数据和排行激发用户抽奖消费;
2、通过技能和宝石等以及转盘的燃爆值,中奖率翻倍等等吸引用户;
3、根本上是为了激发用户活跃性以及刺激消费

技术难点
1、抽奖转盘分为两种转盘,业务逻辑分一个parentVC 管理两个 子 VC;
2、抽奖奖品服务端返回,显示在每一个扇形区域的中间,金额同似;
3、点击抽奖,拿到奖品id, 找出是在转盘中的哪个区域,让转盘指针停止在那一区域;
4、抽奖动态弹幕;
5、燃烧值 和 倒计时的控制;

业务操作说明
1、两个转盘,某个转盘点击开始抽奖 互不影响; 黄金转盘具有宝箱和技能;
2、每抽取一次,扣除相应的金额,如有中奖,则弹出中奖奖品;抽奖分为单次,十连抽,三十连抽等;
3、抽奖后产生记录;在记录中可看到每次抽奖消费情况;
4、转盘有燃烧值,当满时候,触发倒计时3分钟,倒计时内 中奖率将翻倍;
5、燃烧值每3秒刷新一次,当中途离开再次打开,则拿到最新倒计时显示;
6、弹幕从最新100条记录 每隔2秒随机生成一条记录;

模块设计
1、整个框架布局在一个 MainVC中控制转盘类型,请求余额,通知等刷新金额; 管理childVC ;
2、childVC 中 处理抽奖业务逻辑;UI 布局,抽奖请求, 燃烧值处理,弹幕处理;
3、其他功能性子View 单独自定义视图; 转盘视图,燃烧值进度视图,倒计时进度视图, 弹窗类视图;弹幕视图;
4、弹窗类视图 以一个ParentView公共视图容器 ,其中子视图由枚举参数值控制自定义;有玩法视图,记录视图,保险视图,技能视图,排行榜视图;

图片
图片2
当需要在地图上层覆盖一个列表时候,我们想看到更多的内容,列表被拉出来后翻看数据;
当想收起时候,可用下拉,或者随着手势滑落下来;

需解决的问题:
1、滑动表格,地图不移动;手势来回滑时候,列表要跟着高度变化;
2、当滑到最高时候,不再往上滑动;相反,滑到最低高度时候不再继续向下;
3、滑上去之后,再往下滑动 不影响列表数据的查看与浏览;

思考

手势开始:记录 开始点startY,

手势移动:
根据起始位置移动差 确定上滑动 , 下滑动;

起点B 点 记录方向 0;
B-A 正向, 记录方向符号 1;
B-C 反向 ,记录方向 -1;

偏移值 大于0 , 上滑动;
当B-A-C 后,立马记录 1 变成 -1; 记录标记状态前,

正向如:B-A 的过程 ,需判断是否为 为 -1 到1 还是 0-1 , 如果是-1 则是来回拖动;否则为正向拖动;

code :以下是重点逻辑代码;

红包实体,文章实体 都属于动态 ,定义时候实现该协议DynamicPro,相当于java中的接口。
dataList 数组中 存放的是通过网络请求拿到的 DynamicPro 类型的动态列表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
 @protocol DynamicPro <NSObject>
@end

红包实体,文章实体 都属于动态 ,定义时候实现该协议DynamicPro。
dataList 数组中 存放的是通过网络请求拿到的 DynamicPro 类型的动态列表。

DynamicCell: UITableViewCell
{
属性 Id<DynamicPro> dynamic; //文章动态,普通动态,直播动态,红包类型动态
}

@implementation DynamicCell
-(void)setDynamic:(id<DynamicPro>)dynamic{
_dynamic = dynamic;

//DynamicCell 有很多子类cell: 红包cell ,文章cell,直播cell 等
//在子类cell 渲染具体UI数据绑定
}
@end


表格 cellFor 渲染的时候:{

DynamicPro *dynamic = self.dataList[indexPath.row];
DynamicCell * cell = [红包cell new]; //根据dynamic类型 创建 不同的 动态cell
//最终统一设置动态数据
[cell setDynamic: dynamic];
}

表格高度 heightFor 渲染的时候:{

DynamicPro *dynamic = self.dataList[indexPath.row];
if(dynamic 高度不变的){
return 44;
}else{
//高度变动的用自动布局
return UITableViewAutomaticDimension;
}
}

表格 estimatedHeightForRowAtIndexPath 进行自动布局的估算
{
return 100;
}

探究原生网络请求

业务接口API设计与网络请求

Swift 版 Alnofire 框架使用

Swift 中的Json解析

VC 发起请求, 一个专门发请求的发射器;我给它取名字 叫 NetManager , 显然 ,为 了不重复创建http 请求基础配置(请求头,Https证书配置等),这是个单例;

发射器 发的是请求; 考虑到每个业务 都有不同的请求;我准备了 一个 超级父类请求 ;取名 DataRequest; 具体的请求,只需传 具体的子类request;

一个APP 请求有很多,为了区分 及 维护方便 ,于是我定义了一个枚举;每个业务请求,只需给它表明一个标识;

请求具有什么特性呢? 1)有请求的API url地址,2)请求的参数,请求的标识(请求的枚举值), 3)对请求回来的数据解析好封装(业务数据封装等处理); 于是我定义了一个名叫APIInterface 的接口协议; 父类请求去实现这个APInterface接口协议; 子类去Override 这几个方法即可;

发出一个请求,必然有 回答;要么成功,要么失败 (有的失败是业务码失败); 于是 ,我定义了已一个请求回调的接口;RequestCallBackInterface ; (具有三个方法: 业务成功,业务失败,网络其他原因失败)

我从VC 发出去的请求,相当于Android 的Activity; 熟称视图控制器;当然是希望请求回调 回到 视图控制器;
于是我 在 基类视图控制器 BaseViewController 或者BaseActivity(Android) 实现 请求回调 接口协议;实现其中的方法。
具体视图控制器 继承基类, 只需覆盖Override 这三个方法 (具体VC 实现回调后的业务)

最后;页面逻辑就显示得比较简单了,一个单例 NetManager 执行一个 DataRequest (传具体请求子类) ; 视图控制器在具体RequestCallBackInterface 的回调方法 中处理 成功 ,失败后的数据;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//登录请求
self.loginRequest.userLogin = self.userName;
self.loginRequest.userPass = self.userPwd;
[[GYNetworkingManager shareInstance] executeRequest:self.loginRequest];

//朋友圈列表请求
self.dynamicListRequest.pageIndex = 1;
self.dynamicListRequest.pageSize = 20;
[[GYNetworkingManager shareInstance] executeRequest:self.dynamicListRequest];

-(void) onRequestSuccess:(BaseResponse *)response
{
switch (response.requestAPICode ) { //请求的枚举
case Http_Login:
{
//返回的登录对象
// LoginData *data = response.responseObject;
break;
}
case Http_DynamicList:
{
//如果是列表,则从取数组
NSArray *dataList = response.tableList.dataList;
[self allLoadingCompleted:dataList];
break;
}

default:
break;
}
}

AFNetworking也被广泛使用。其它的ASIHttpRequest,MKNetworkKit啥的其实也都还不错,苹果对网络请求部分已经做了很好的封装。但不管如何,APP端还是要对网络进行一个封装。在实际的App开发中,Afnetworking已经成为了事实上各大App的标准配置。

iOS开发领域有很多对象间数据的传递方式,我看到的大多数App在网络层所采用的方案主要集中于这三种:Delegate,Notification,Block。我的意见是Delegate为主,Notification可以用在网络发生变化时候使用。

ios线程形式有三种。 ios4后,苹果改用GCD多线程。线程可以用来干什么呢?多线程可以用来后台加载图片更新主线程UI,或者请求网络数据等等。

Thread

使用 NSThread 来创建线程有两种方法:

1
2
3
4
5
6
7
8
[NSThread detachNewThreadSelector:@selector(myThreadMainMethod:) toTarget:self withObject:nil];

NSThread* myThread = [[NSThread alloc] initWithTarget:self

selector:@selector(myThreadMainMethod:)

object:nil];
[myThread start]; // Actually create the thread