日期: 2021 年 6 月 10 日

ping 一会通一会不通

我自己电脑的原因:

原因是局域网有多个交换机,导致经常被攻击,后来开了局域网防护,

主机上有电脑管家/360等防护软件,ping不通对方

 

解决方案:
打开360->功能大全->流量防火墙->局域网防护->*下面 局域网隐身关闭就可以了。

这个问题还会导致局域网共享发布后,别的电脑访问不了。

 

1.网卡重启
2.ping 127.0.0.1 测试本地网卡
3.tracert IP
4.对端ping本端 对端指定源ip
5.网络抓包工具
6.本端或端口是否开启防火墙,端口是否放行icmp,安全策略是否放行
7.是否有ip冲突,本地地址冲突或者对端地址冲突
8.是否有带宽挤占,下载文件占用大量带宽

同一网段下的电脑ping不通的几种原因

  1. 防火墙问题,两台机器的防火墙没有关闭
  2. 系统——>高级系统设置——>远程——>勾选允许远程协助

%title插图%num

目前遇到这两种问题导致的两台机器ping不通;
另外win10默认不开启telnet服务,需要手动开启,测试连接另一个电脑端口通不通:

telnet ip port
  • 1

回车后,连接成功后会弹一个新的黑窗口

iOS 获取当前正在显示的ViewController

适用范围,在APPDelegate中需要获取当前显示的vc(比如来了新的推送), tabbar的子视图都是NavigationController,其它情况可以根据情况调整

+ (UIViewController *)getCurrentVC{

UIWindow * window = [[UIApplication sharedApplication] keyWindow];
//app默认windowLevel是UIWindowLevelNormal,如果不是,找到UIWindowLevelNormal的
//其他框架可能会改我们的keywindow,比如支付宝支付,qq登录都是在一个新的window上,这时候的keywindow就不是appdelegate中的window。 当然这里也可以直接用APPdelegate里的window。
if (window.windowLevel != UIWindowLevelNormal)
{
NSArray *windows = [[UIApplication sharedApplication] windows];
for(UIWindow * tmpWin in windows)
{
if (tmpWin.windowLevel == UIWindowLevelNormal)
{
window = tmpWin;
break;
}
}
}

UIViewController* currentViewController = window.rootViewController;
while (YES) {
if (currentViewController.presentedViewController) {
currentViewController = currentViewController.presentedViewController;
} else {
if ([currentViewController isKindOfClass:[UINavigationController class]]) {
currentViewController = ((UINavigationController *)currentViewController).visibleViewController;
} else if ([currentViewController isKindOfClass:[UITabBarController class]]) {
currentViewController = ((UITabBarController* )currentViewController).selectedViewController;
} else {
break;
}
}
}

return currentViewController;

}
这里讲一下实现思路, 我们想要与控制器无耦合的情况下, 想要直接获取到当前控制器, 基本都是通过 rootViewController 来查找的, 通过上面的方法拿到 rootViewControoler 之后, 我们先看 presentedViewController, 因为控制器呈现出来的方式有 push 与 present, 我们先查看它是否是 present 出来的, 如果是则通过此属性能找到 present 出来的当前控制器, 然后在检查是否属于 UINavigationControler 或 UITabBarController ,如果是则通过查找其子控制器里面*顶层或者其正在选择的控制器。 *后在判断当前控制器是否有子控制器的情况, 如果有则取其子控制器*顶层, 否则当前控制器就是其本身。

这里主要是查找当前 应用程序基于 UITabBarController 和 UINavigationControler 下管理的视图控制器, 如果还有其他控制器则需要添加 if 条件来进行判断。

presentedViewController
Apple 文档 presentedViewControlle

通过此方法可以查找到通过 presented 模态方式(显示与隐士) 方式推出的当前控制器。 例如: AViewController –> BViewController 通过模态方式推出. 则使用 AViewController.presentedViewController 能获取到 BViewController。

presentingViewController
Apple 文档

通过此方法可以查找到通过 presented 模态方式(显示与隐士) 方式推出当前控制器的上层控制器。 例如: AViewController –> BViewController 通过模态方式推出. 则使用 BViewController.presentingViewController 能获取到 AViewController。

还有一种写法 , 在一个普通的UIView或者UIView子类中,需要找到离这个View*近的ViewController , 可以写一个类别

#import <UIKit/UIKit.h>

@interface UIView (ViewController)
– (UIViewController *)viewController;
@end

#import “UIView+ViewController.h”

@implementation UIView (ViewController)

– (UIViewController *)viewController
{
UIResponder *next = [self nextResponder];

do {
if ([next isKindOfClass:[UIViewController class]]) {
return (UIViewController *)next;
}
next = [next nextResponder];
} while (next != nil);
return nil;
}

@end
 

– (nullableUIResponder*)nextResponder  解释

问题1。 如何调用父view的controller里面的方法?

答案如下:
[[self superview ].nextResponder  method];
[[[self superview ] nextResponder]  method];
[self.nextResponder method];
上面的都可以,看情况使用,使用的时候*好判断一下。

官方解释
UIView implements this method by returning the UIViewController object that manages it (if it has one) or its superview (if it doesn’t); UIViewController implements the method by returning its view’s superview; UIWindow returns the application object, and UIApplication returns nil.

UIView实现了这个方法通过返回对应的ViewController或者这个view的父视图;

UIViewController实现了这个方法返回这个view的父视图;

UIWindow返回UIApplication对象;

UIApplication 返回nil。

问题2:当一个子view需要接收点击事件,而父view也需要接收点击事件, 如何做?

当然, 你可能会说直接调用mysubview.superView即可, 这样做也确实是可以做到,但有时子view是不一定知道有这个特定的父view的存在的,如动态添加子view。

所以这里就可以用到消息响应链拉技术。

下面要做的也就是,让子view接收这些事件后,同时把这些事件继续向上传,会一直传到UIApplication为止。 而在传的过程中,如果子view接收了这些事件,那么事件会自然终止,我们现在可以做的是同时让子view接收事件,而且还让事件不终止,并继续向上传。

摘取一部分说明:

“当用户  与  iPhone的触摸屏  产生  互动时,硬件  就会探测到  物理接触  并且  通知  操作系统。接着  操作系统  就会创建  相应的事件  并且  将  其  传递给  当前正在运行的应用程序的事件队列。然后  这项事件  会被事件循环  传递给  优先响应者物件。优先响应者物件  是  事件  被触发时  和  用户  交互的物件,比如  按钮物件、视图物件。如果  我们  编写了  代码  让  优先响应者  处理  这种类型的事件,那么  它  就会处理  这种类型的事件。处理完  某项事件后,响应者  有  两个选项:1、将  其  丢弃;2、将  其  传递给  响应链条中的下一个响应者。下一个响应者的地址   存储  在当前响应者物件所包含的变量nextResponder当中。如果  优先响应者  无法处理  一项事件,那么  这项事件  就传递给  下一个响应者,直到  这项事件  到达  能处理它的响应者  或者  到达  响应链条的末端,也就是  UIApplication类型的物件。UIApplication类型的物件  收到  一项事件后,也是  要么  处理,要么  丢弃。“

比如  有  一个视图物件,这个视图物件上  有  一个按钮物件。当用户  触摸  这个按钮物件时,作为优先响应者,这个按钮物件  就会收到  一项事件。如果  这个按钮物件  无法处理  这项事件,就会将  这项事件  传递给  视图物件。如果  视图物件  无法处理  这项事件,就会将  这项事件  传递给  视图控制器物件。以此类推。

应该注意的  是  当我们  在使用  响应链条时,一项事件  并不会自动地  从一个响应者  传递到  下一个响应者。如果  要将  一项事件  从一个响应者  传递到  下一个响应者,我们  必须编写  代码  才能办到。”

要做的如下:

子view的代码如下:

– (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{

// 这里可以做子view自己想做的事,做完后,事件继续上传,就可以让其父类,甚至父viewcontroller获取到这个事件了

[[self nextResponder]touchesBegan:toucheswithEvent:event];

}

– (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{

[[self nextResponder]touchesEnded:toucheswithEvent:event];

}

– (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{

[[self nextResponder] touchesCancelled:toucheswithEvent:event];

}

– (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{

[[self nextResponder] touchesMoved:toucheswithEvent:event];

}
另外需要注意的是:在重写这几个方法时,*好保证这几个方法都重写,否则事件响应链可能会变混乱。这是我的猜测哈,没有实际验证过。

 

还有一种方法, cocoa在 app 生命周期变化是注册了系统级的通知,我们只需要在viewcontroller中监听一下就行,下面是常用通知的名字  ,   还有很多, 写一个 command 进去看看吧 .

UIKIT_EXTERN NSNotificationName const UIApplicationDidFinishLaunchingNotification;

UIKIT_EXTERN NSNotificationName const UIApplicationDidBecomeActiveNotification;

UIKIT_EXTERN NSNotificationName const UIApplicationWillResignActiveNotification;

UIKIT_EXTERN NSNotificationName const UIApplicationDidReceiveMemoryWarningNotification;

UIKIT_EXTERN NSNotificationName const UIApplicationWillTerminateNotification
 

 

 

 

IOS启用WebApp全屏模式

分享一段代码实例,它实现了IOS启用WebApp全屏模式的功能。

当网站添加到主屏幕后再点击进行启动时,可隐藏地址栏(从浏览器跳转或输入链接进入并没有此效果)

代码实例如下:

1
2
< meta name = "apple-mobile-web-app-capable" content = "yes" />
< meta name = "apple-touch-fullscreen" content = "yes" />

ios 全屏返回手势

前言

苹果在IOS7以后给导航控制器增加了一个Pop的手势,只要手指在屏幕边缘滑动,当前的控制器的视图就会跟随你的手指移动,当用户松手后,系统会判断手指拖动出来的大小来决定是否要执行控制器的Pop操作。

%title插图%num

这个操作的想法非常好,但是系统给我们规定的范围必须是屏幕左侧边缘才可以触发,这样实际使用过程中对于有些产品会产生不便,于是有些app就采取整个屏幕都响应这个手势并且pop动画还是用系统原生的,这样操作起来确实方便好多。

%title插图%num

 

推荐使用:Runtime+KVC

为了方便大家阅读下面的代码,我们需要先了解系统的这个手势。

前面我们了解到,这个手势属于UINavigationController,我们就跳到它的头文件里看看能不能找到线索。这个思路是正确的,确实有一个手势叫做interactivePopGestureRecognizer。属性为readonly,就是说我们不能给他换成自定义的手势,但是可以设置enable=NO。ok,既然找到了它,就打印一下看看它到底是一个什么手势。

%title插图%num

通过log,我们看到他属于UIScreenEdgePanGestureRecognizer这个类(之前我是没有用到过),它继承自UIPanGestureRecognizer,出现在IOS7以后,是专门处理在屏幕边缘触发的手势类型,并且只有一个属性叫edges,用来设置它的触发边缘(上、下、左、右、全部)。

我们继续看它的log。控制台除了打印了它的类,还打印了它的触发target:_UINavigationInteractiveTransition(这是一个私有类,看来是专门用来做导航控制器交互动画的),和action:handleNavigationTransition(这是它的一个私有方法),我们要做的就是新建一个UIPanGestureRecognizer,让它的触发和系统的这个手势相同,这就需要利用runtime获取系统手势的target和action。

那么如何获取这个target呢?一开始我用kvc想直接获取这个手势的target,程序崩溃了,原来它根本没有这样一个属性。所以我能想到的是,先利用runtime遍历它的所有成员变量,看看系统是怎么存储这个属性的,

 

%title插图%num

 

通过log我们可以看到,UIGestureRecognizer有一个叫_targets的属性,它的类型为NSMutableArray。

%title插图%num

它是用数组来存储每一个target-action,所以可以动态的增加手势触发对象。那么又是什么存储每一个target-action呢?为了了解这个我们拿到这个属性的名字”_targets”通过kvc获取它,接着打印出来。

%title插图%num

 

%title插图%num

可以看到,由于系统重写了它的description方法,所以我们没办法通过打印获取这个对象是什么类型。既然不能打印,那么我们就用断点调试,来看它的真实类型,

%title插图%num

我们看到,原来每一个target-action是用UIGestureRecognizerTarget这样一个类来存储的,它也是一个私有类。
苹果把许多的类做私有化也是有原因所在,其实在平时我们拿到这个类也是没有用的,他们的目的之一是避免对开发者公开无用的类,影响了封装性。所以在类的设计上,还是要向苹果学习。

下面直接看代码。

我们在控制器的ViewDidLoad加上这段代码,并且它只需要执行一次。

 

%title插图%num

 

优化

这个demo我会提供给大家,下面简单说下程序的优化思路。

  • 优化点一:对于方案一,其实不应该把导航控制器的代理方法以及手势处理的方法交给视图控制器,因为这段代码不是属于某一个视图控制器,而是全局的导航控制器,所以我们应该参考苹果的设计思想:新建一个专门管理交互过程的对象,这个类我们叫做NavigationInteractiveTransition。
  • 优化点二:再来看之前的ViewDidLoad中只执行一次的代码,其实写在这里也不够妥当,同样的,这段代码也不属于某一个Controller,优化方案是新建一个导航控制器,在这个导航控制器的viewDidLoad中写上这些代码,这样也并不需要dispatch once。
  • 优化点三:由于我们自定义的手势是加在一个私有view上,这个view是一个全局的,所以当这个控制器为根控制器时,我们的手势还是在起作用,这就相当于对根控制器做了pop操作,这会出现一个错误nested pop animation can result in corrupted navigation bar。导致这个错误的原因还有一个,如果我们pop的动画正在执行,再去触发一次手势,会导致导航控制器和导航条的动画混乱。为了避免问题出现我们需要成为手势的代理,判断当前控制器是否为根控制器并且pop或者push动画是否在执行(这个变量是私有的,需要用kvc来获取)。

    %title插图%num

    经过*后的优化,视图控制器可以什么都不写,想使用这个效果,只要使用我们自定义的导航控制器就可以了,这样的好处是手势动画与控制器完全解耦,并且不用给每一个控制器都addGesture。


给大家推荐一个仓库https://github.com/nst/iOS-Runtime-Headers,这个仓库可以调取苹果的所有私有方法头文件,相当强大。

*后放上这个demo的地址:https://github.com/zys456465111/CustomPopAnimation(使用时,切换工程的scheme就能切换不同方案。对于方案二,只需要导航控制器的类就可以了。)

pod ‘FDFullscreenPopGesture’

还发现了一个问题, 比如前一个页面是没有NavigationBar , 后一个页面有NavigationBar , *好在前一个页面通过这种方式设置导航栏隐藏,如果直接使用     self.navigationController.navigationBarHidden = YES ;  没有设置动画的, 通过手势pop回来的时候,导航栏的位置是有很强的割裂感,嗯,就是很丑.

  1. – (void)viewWillAppear:(BOOL)animated {
  2. [super viewWillAppear:animated];
  3. [self.navigationController setNavigationBarHidden:YES animated:animated];
  4. }

 

IOS 通过界面图标启动Web应用 + 全屏应用 + 添加到主屏幕

请注意!!!使用了【全屏模式之后】。页面的顶部会空出一大块。而且这并不属于margin,padding,或者定位。就是单纯的空出来非常难调试。其实坑就是这里

 

在 iPhone「添加到主屏幕」时显示自定义图标

测试资源下载:https://github.com/dragon8github/mobile-boilerplate/tree/master/img/touch

<!doctype html>
<html>
  <head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <!-- iPad and iPad mini (with @2× display) iOS ≥ 8 -->
        <link rel="apple-touch-icon-precomposed" sizes="180x180" href="img/touch/apple-touch-icon-180x180-precomposed.png">
        <!-- iPad 3+ (with @2× display) iOS ≥ 7 -->
        <link rel="apple-touch-icon-precomposed" sizes="152x152" href="img/touch/apple-touch-icon-152x152-precomposed.png">
        <!-- iPad (with @2× display) iOS ≤ 6 -->
        <link rel="apple-touch-icon-precomposed" sizes="144x144" href="img/touch/apple-touch-icon-144x144-precomposed.png">
        <!-- iPhone (with @2× and @3 display) iOS ≥ 7 -->
        <link rel="apple-touch-icon-precomposed" sizes="120x120" href="img/touch/apple-touch-icon-120x120-precomposed.png">
        <!-- iPhone (with @2× display) iOS ≤ 6 -->
        <link rel="apple-touch-icon-precomposed" sizes="114x114" href="img/touch/apple-touch-icon-114x114-precomposed.png">
        <!-- iPad mini and the first- and second-generation iPad (@1× display) on iOS ≥ 7 -->
        <link rel="apple-touch-icon-precomposed" sizes="76x76" href="img/touch/apple-touch-icon-76x76-precomposed.png">
        <!-- iPad mini and the first- and second-generation iPad (@1× display) on iOS ≤ 6 -->
        <link rel="apple-touch-icon-precomposed" sizes="72x72" href="img/touch/apple-touch-icon-72x72-precomposed.png">
        <!-- Android Stock Browser and non-Retina iPhone and iPod Touch -->
        <link rel="apple-touch-icon-precomposed" href="img/touch/apple-touch-icon-57x57-precomposed.png">
        <!-- Fallback for everything else -->
        <link rel="shortcut icon" href="img/touch/apple-touch-icon.png">
        
        <!-- IOS 主屏幕应用全屏 -->
        <meta name="apple-mobile-web-app-capable" content="yes">
        <!-- 安卓 主屏幕应用全屏 -->
        <meta name="mobile-web-app-capable" content="yes">

<!– IOS默認的時間、電池、供應商等信息 –>
<meta name=”apple-mobile-web-app-status-bar-style” content=”black” />

  </head>
  <body>
  </body>
</html>

 

效果演示(Safari浏览器才支持【添加到主屏幕】,坑爹的UC浏览器不支持):

%title插图%num

在桌面显示的是自定义的ICO图标

%title插图%num

由于加入了<meta name=”apple-mobile-web-app-capable” content=”yes”>

所以通过桌面启动的网站是全屏显示的(隐藏了浏览器的地址栏和工具栏,加载状态栏等)

%title插图%num

IOS界面全屏模式

如果只是想把当前页面的状态栏隐藏的话,直接用下面的代码就可以

[[UIApplication sharedApplication] setStatusBarHidden:TRUE];

如果你要在整个app中把提示栏隐藏,使用全屏模式,需要在Info.plist中进行如下设置:

Status bar is initially hidden    YES

View controller-based status bar appearance  NO

iOS常用方法——UIWebView全屏显示的实现

项目中加载webView,导航栏由web端做的话,客户端就需要隐藏掉导航栏。这个时候显示出来的页面,在顶部会出现状态栏为空白的问题。底部也会多出空白,即:

– (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor whiteColor];
UIWebView * view = [[UIWebView alloc] initWithFrame:self.view.frame];
view.backgroundColor = [UIColor redColor];
[self.view addSubview:view];
}

效果如图:

%title插图%num

%title插图%num

只需要将代码做如下修改,就可以解决以上问题,实现全屏:

– (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor whiteColor];
UIWebView * view = [[UIWebView alloc] initWithFrame:self.view.frame];
view.backgroundColor = [UIColor redColor];
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 11) {
view.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}else{
self.edgesForExtendedLayout = UIRectEdgeNone;
}
[self.view addSubview:view];
}

亲试有效的哦~注意要判断一下系统的版本,scrollView.contentInsetAdjustmentBehavior这个属性时iOS11后添加的,如果版本号没到11,可能会崩溃。

iOS组件化开发从开始到完整总结

一.组件化介绍
需求来源
随着项目规模不断扩大,业务模块增多,开发过程中会有多条产品线(多人或多小组开发不同的功能);如果用传统的开发模式,会导致代码臃肿,编译速度越来越慢,开发效率低下,代码维护成本越来越高.

组件化优势
代码逻辑和项目结构清晰;代码利用率高,迭代效率高;可以快速集成,并能做单元测试;每个组件可以单独运行,组件之间的耦合度低.

组件化模块划分
基础组件: 宏定义/自定义分类/自定义工具类
功能组件: 项目中常用功能,如:定位/推送/分享
业务组件: 根据具体业务而定,如:聊天/商城
中间组件: 负责界面路由/传参/回调
宿主工程: 类似一个壳子,组合各个组件,形成一个完整的App

组件化实质
组件化其实是把每一个功能模块拆分成一个一个的Pod库;比如项目中要用到AFN,只要Pod一下,便触手可及~;现在我们制作自己的Pod库,然后把它集成到项目中.

二.需要了解
Trunk账号
认证CocoaPods API的服务
用来管理公共仓库中的自己的组件
索引文件(.podspec文件)
记录一个组件的名称/版本/资源储存路径/维护者信息等
每个组件都必须有一个索引文件
索引文件库(Spec Repo)
存放索引文件的仓库
储存在CocoaPods服务器上,我们下载或更新Pod的时候会把这个仓库拷贝一份到本地,本地存放路径:~/.cocoapods/repos/
CocoaPods提供一个公共库,储存在本地的路径为:~/.cocoapods/repos/master/
我们可以创建私有仓库,储存在本地的路径为:~/.cocoapods/repos/自定义仓库名/
组件模板
CocoaPods提供用于快速创建组件的模板
里边可以制作我们的代码,可以做单元测试等,包含一个对应的索引文件
组件化就是以这个模板为基础,制作自己的组件
三.思路梳理(注意划重点了)
有了以上基础知识的了解我们来梳理一下思路
本文会使用私有索引仓库来维护组件(不使用公共仓库master)
组件添加到公共仓库中需要注册Trunk账号:  传送门
在码云(或者其他Git仓库)创建一个私有的仓库,当做<私有索引文件仓库>,后边用来储存索引文件(项目名称:xxSpecs)
在码云(或者其他Git仓库)创建一个公开的仓库,当做<组件仓库>,后边用来储存组件(项目名称:xxKit)
CocoaPods服务器不储存我们的代码,只储存索引文件
制作好组件之后,索引文件里会储存<组件仓库>的地址,把索引文件传给CocoaPods服务器,告诉它储存在指定的<私有索引文件仓库>
使用时,先通过CocoaPods服务器更新<私有索引文件仓库>到本地;项目中Pod某个组件的时候,会在本地<私有索引文件仓库>中找到这个组件的索引文件,从索引文件里拿到<组件仓库>的地址,从这个地址把代码下载到项目中
总结:思路梳理介绍了组件化制作过程的主干,只要大体明白我们在干什么,下边具体操作时会有详细步骤
四.具体操作
索引文件仓库

关联索引文件仓库
把码云上创建的索引文件仓库关联拷贝到本地
pod repo add [仓库名] [仓库URL地址]
之后输入远端Git仓库的账号和密码
检查是否安装成功
cd 到索引文件仓库
cd ~/.cocoapods/repos/[仓库名]
验证索引文件仓库
pod repo lint .
组件

本地新建一个文件夹,用于存放管理组件(起名:xxPod)
下载组件模板到xxPod文件夹
cd 到xxPod文件夹
cd [文件夹全路径]/xxPod
下载组件模板并设置组件名
[组件名] : xxKit (跟码云上组件仓库的名字一致)
pod lib create [组件名]
组件基本设置
// 使用哪种系统的模板
What platform do you want to use?? [ iOS / macOS ]
> ios
// 使用哪种语言
What language do you want to use?? [ Swift / ObjC ]
> objc
// 是否创建测试Demo
Would you like to include a demo application with your library? [ Yes / No ]
> yes
// 使用哪种测试框架
Which testing frameworks will you use? [ Specta / Kiwi / None ]
> specta
// 是否需要测试视图
Would you like to do view based testing? [ Yes / No ]
> yes
// 测试Demo的类前缀
What is your class prefix?
> XX
代码制作
把自己的代码(类文件)直接复制到xxPod/xxKit/xxKit/Classes里
配置组件索引文件:  传送门
检查索引文件格式是否规范
cd 到组件根目录
cd [文件夹全路径]/xxPod/xxKit
检查本地索引文件(passed validation 表示通过验证;–allow-warnings可忽略警告)
pod lib lint
如果提示标签类错误可暂时不用管,往下继续
制作好的代码Pod到组件测试工程中(可进行编译,运行,发现代码问题)
cd 到组件的Example文件夹
cd [文件夹全路径]/xxPod/xxKit/Example
Pod集成
pod install
把做好的组件推送到自己的组件仓库
cd 到组件根目录
cd [文件夹全路径]/xxPod/xxKit/
初始化git
git init
git add .
提交一个Git版本
git commit -m “xxKit组件初始化”
关联码云上的组件仓库
git remote add origin [组件仓库URL]
推送版本到master分支(-f强制推送,覆盖掉之前的所有文件)
git push origin master -f
添加版本标签(标签号必须与索引文件里的标签号一致)
git tag 0.1.0
标签推送到组件仓库
git push –tags
检查远程索引文件(passed validation 表示通过验证)
pod spec lint
关联CocoaPods服务器

制作好的组件关联CocoaPods服务器
cd 到xxKit组件根目录
cd [文件夹全路径]/xxPod/xxKit
推送组件的索引文件到服务器,并告诉服务器存在哪个私有仓库中
[私有仓库名] : xxSpecs
[组件名] : xxKit
pod repo push [私有仓库名] [组件名].podspec –allow-warnings
查看本地的CocoaPods仓库(可看到公共库和自己的私有库)
pod repo
检查组件
更新本地CocoaPods仓库
pod repo update
搜索刚才制作的组件
[组件名] : xxKit
pod search [组件名]
项目中引用私用组件

新建一个项目工程,并添加Pod
配置Podfile文件
全局添加(<私有索引文件仓库>地址)
source ‘https://gitee.com/xxSpecs.git’
单独添加(<组件仓库>地址)
pod ‘xxKit’, :git => ‘https://gitee.com/xxKit.git’
五.iOS组件化开发架构设计

%title插图%num

%title插图%num
六.iOS组件化方案探索
一、什么是组件化?
1、什么是组件?
“组件”一般来说用于命名比较小的功能块,如:下拉刷新组件、提示框组件。而较大粒度的业务功能,我们习惯称之为”模块”,如:首页模块、我的模块、新闻模块。

这次讨论的主题是组件化,这里为了方便表述,下面模块和组件代表同一个意思,都是指较大粒度的业务模块。

2、什么是组件化?
组件化,或者说模块化,用来分割、组织和打包软件。每个模块完成一个特定的子功能,所有的模块按某种方法组装起来,成为一个整体,完成整个系统所要求的功能。

从工程代码层面来说,组件化的实施通常是通过中间件解决组件间头文件直接引用、依赖混乱的问题;从实际开发来说,组件之间*大的需求就是页面跳转,需要从组件A的pageA页面跳转到组件B的pageB页面,避免对组件B页面ViewController头文件的直接依赖。

二、为什么要组件化?
1、组件化是为了解决什么问题?
一个 APP 有多个模块,模块之间会通信,互相调用,如我们的app,有首页、行情、资讯、我的等模块。这些模块会互相调用,例如 首页底部需要展示部分资讯、行情;行情底部需要展示个股资讯;资讯详情页需要跳转到行情,等等。

2、组件化的好处?
一般意义:

加快编译速度(不用编译主客那一大坨代码了);
各组件自由选择开发姿势(MVC / MVVM / FRP);
组件工程本身可以独立开发测试,方便 QA 有针对性地测试;
规范组件之间的通信接,让各个组件对外都提供一个黑盒服务,减少沟通和维护成本,提高效率;
对于公司已有项目的现实意义:

业务分层、解耦,使代码变得可维护;
有效的拆分、组织日益庞大的工程代码,使工程目录变得可维护;
便于各业务功能拆分、抽离,实现真正的功能复用;
业务隔离,跨团队开发代码控制和版本风险控制的实现;
模块化对代码的封装性、合理性都有一定的要求,提升开发同学的设计能力;
在维护好各级组件的情况下,随意组合满足不同客户需求;(只需要将之前的多个业务组件模块在新的主App中进行组装即可快速迭代出下一个全新App)
3、什么情况下进行组件化比较合适?
当然组件化也有它的缺点:

学习成本高,对于开发人员对各种工具的掌握要求也比较高,对于新手来说入门较为困难。

由于工具和流程的复杂化,导致团队之间协作的成本变高,某些情况下可能会导致开发效率下降。

当项目App处于起步阶段、各个需求模块趋于成熟稳定的过程中,组件化也许并没有那么迫切,甚至考虑组件化的架构可能会影响开发效率和需求迭代。

而当项目迭代到一定时期之后,便会出现一些相对独立的业务功能模块,而团队的规模也会随着项目迭代逐渐增长,这便是中小型应用考虑组件化的时机了。这时为了更好的分工协作,团队安排团队成员各自维护一个相对独立的业务组件是比较常见的做法。

在这时这个时候来引入组件化方案,是比较合适的时机。长远来看,组件化带来的好处是远远大于坏处的,特别是随着项目的规模增大,这种好处会变得越来越明显

三、如何组件化?
1、如何划分组件?
基础功能组件
基础产品组件
个性化业务组件
对于一个没有实施过组件化拆分的工程来说,其中很可能充满了大量不合理的类、方法、头文件和各种错乱的依赖关系,因此首先要进行的*步是模块拆分。

模块拆分可以分成两个部分,基础模块拆分和业务模块拆分。基础模块通常是稳定的依赖代码,业务模块是涉及到业务的需要频繁改动的代码。

基础模块拆分

基础模块是任何一个App都需要用到的,如:性能统计、Networking、Patch、网络诊断、数据存储模块。对于基础模块来说,其本身应该是自洽的,即可以单独编译或者几个模块合在一起可以单独编译。所有的依赖关系都应该是业务模块指向基础模块的。
基础模块之间尽量避免产生横向依赖。

业务模块拆分

对于业务模块来说,考虑到旧有代码可能没有相关的横向解耦策略,业务模块之间的依赖会非常复杂,难以单独进行拆分,因此我们采用的方法是首先从 group 角度进行重新整理。

对业务量很大的工程来说,我个人更加推荐“业务-分层”这样的结构,而不是“分层-业务”,即类似下面的 group 结构:

– BusinessA
– Model
– View
– Controller
– Store
– BusinessB
– Model
– View
– Controller
-Store

而非目前项目中采用的:

– Controllers
– BusinessA_Controller
– BusinessB_Controller
– Views
– BusinessA_View
– BusinessB_View
– Models
– BusinessA_Model
– BusinessB_Model

2、组件化的技术难点?
组件化的实施,直观上看,只是需要将各业务组件的代码放到各自的文件夹或者 jar包里就行了。

这里引出的是:

2.1、组件的拆分方式问题:

可以利用CocoaPods 配合 git 做代码版本管理,独立业务模块单独成库。

但这仅仅是物理上拆分了,拆分后的代码编译是肯定通不过的,因为如下:

#import “MainViewController.h”
#import “HomeViewController.h”
#import “NewsViewController.h”
#import “MeViewController.h”
#import …

@implementation MainViewController

@end

MainViewController 会找不到依赖的其它各个模块的头文件而报错。这里引出的又是另一个问题:

2.2、组件间如何解耦?

组件间解耦,是组件化必须解决的一个问题。换句话说,就是如何解除业务模块间的横向依赖。还是拿上边举得例子来说:

App的根视图MainViewController需要管理首页、新闻、我的等等页面时,如何做到 MainViewController 中,不用去 import这一大堆 XXViewController ?

很简单,按软件工程的思路,下意识就会加一个中间层Mediator:

%title插图%num

这样一来,各个模块直接都不需要再互相依赖,而是仅需要依赖 Mediator 层即可。

可直观上看,这样做并没有什么好处,依赖关系并没有解除,Mediator 依赖了所有模块,而调用者又依赖 Mediator,*后还是一坨互相依赖,跟原来没有 Mediator 的方案相比除了更麻烦点其他没区别。

我们希望*终能过实现的是单向的依赖,即:

%title插图%num

七.组件化细分设计
一.组件化方案中的去model设计
组件间调用时,是需要针对参数做去model化的。如果组件间调用不对参数做去model化的设计,就会导致业务形式上被组件化了,实质上依然没有被独立。
假设模块A和模块B之间采用model化的方案去调用,那么调用方法时传递的参数就会是一个对象。如果对象不是一个面向接口的通用对象,那么mediator的参数处理就会非常复杂,因为要区分不同的对象类型。如果mediator不处理参数,直接将对象以范型的方式转交给模块B,那么模块B必然要包含对象类型的声明。假设对象声明放在模块A,那么B和A之间的组件化只是个形式主义。如果对象类型声明放在mediator,那么对于B而言,就不得不依赖mediator。对于响应请求的模块而言,依赖mediator并不是必要条件,因此这种依赖是完全不需要的,这种依赖的存在对于架构整体而言,是一种污染。
如果参数是一个面向接口的对象,那么mediator对于这种参数的处理其实就没必要了,更多的是直接转给响应方的模块。而且接口的定义就不可能放在发起方的模块中了,只能放在mediator中。响应方如果要完成响应,就也必须要依赖mediator,然而前面我已经说过,响应方对于mediator的依赖是不必要的,因此参数其实也并不适合以面向接口的对象的方式去传递。
因此,使用对象化的参数无论是否面向接口,带来的结果就是业务模块形式上是被组件化了,但实质上依然没有被独立。在这种跨模块场景中,参数*好还是以去model化的方式去传递,在iOS的开发中,就是以字典的方式去传递。这样就能够做到只有调用方依赖mediator,而响应方不需要依赖mediator。然而在去model化的实践中,由于这种方式自由度太大,我们至少需要保证调用方生成的参数能够被响应方理解,然而在组件化场景中,限制去model化方案的自由度的手段,相比于网络层和持久层更加容易得多。
因为组件化天然具备了限制手段:参数不对就无法调用!无法调用时直接debug就能很快找到原因。所以接下来要解决的去model化方案的另一个问题就是:如何提高开发效率。
在去model的组件化方案中,影响效率的点有两个:调用方如何知道接收方需要哪些key的参数?调用方如何知道有哪些target可以被调用?其实后面的那个问题不管是不是去model的方案,都会遇到。为什么放在一起说,因为我接下来要说的解决方案可以把这两个问题一起解决。
二.解决方案就是使用category
mediator这个repo维护了若干个针对mediator的category,每一个对应一个target,每个category里的方法对应了这个target下所有可能的调用场景,这样调用者在包含mediator的时候,自动获得了所有可用的target-action,无论是调用还是参数传递,都非常方便。接下来我要解释一下为什么是category而不是其他:
category本身就是一种组合模式,根据不同的分类提供不同的方法,此时每一个组件就是一个分类,因此把每个组件可以支  持的调用用category封装是很合理的。
在category的方法中可以做到参数的验证,在架构中对于保证参数安全是很有必要的。当参数不对时,category就提供了补救的入口。
category可以很轻松地做请求转发,如果不采用category,请求转发逻辑就非常难做了。
category统一了所有的组件间调用入口,因此无论是在调试还是源码阅读上,都为工程师提供了*大的方便。
由于category统一了所有的调用入口,使得在跨模块调用时,对于param的hardcode在整个App中的作用域仅存在于category中,在这种场景下的hardcode就已经变成和调用宏或者调用声明没有任何区别了,因此是可以接受的。

iOS 各种项目源码集

一:源代码实例

1:快速搭建项目源代码

地址:https://github.com/wujunyang/MobileProject

2:高仿美团iOS版

地址:https://github.com/lookingstars/meituan

3:模仿网易新闻做的精仿网易新闻

地址:https://github.com/dsxNiubility/SXNews

4:支付宝高仿版

地址:https://github.com/gsdios/GSD_ZHIFUBAO

5:高仿百度传课iOS版

地址:https://github.com/lookingstars/chuanke

6:模仿一元云购

地址:https://github.com/JxbSir/YiYuanYunGou

7:wordpress源代码

地址:https://github.com/wordpress-mobile/WordPress-iOS

8:v2ex源代码(文章类型,若报SVProgressHUD错,则把Podfile中的SVProgressHUD移除)

地址:https://github.com/singro/v2ex

9:PHPHub客户端(IOS8.0以上)

地址:https://github.com/Aufree/phphub-ios

10:Coding.NET客户端

地址:https://coding.net/u/coding/p/Coding-iOS/git

11:如何优化UITableView中Cell加载图片的实例

地址:https://github.com/allenhsu/UIScrollView-Samples/tree/master/LazyLoad

12:开源的IOS代码集合

地址:https://github.com/dkhamsing/open-source-ios-apps

二:辅助软件

1:XCODE文档注解插件VVDocumenter

地址:https://github.com/onevcat/VVDocumenter-Xcode

2:将JSON格式化输出为模型的属性

地址:https://github.com/EnjoySR/ESJsonFormat-Xcode

3:图片提示插件

地址:https://github.com/ksuther/KSImageNamed-Xcode

4:图片转换插件

地址:https://github.com/rickytan/RTImageAssets

5:测试模拟苹果通知

地址:https://github.com/KnuffApp/Knuff

6: HOStringSense可以在弹出框写NSString,所见及所得

地址:https://github.com/holtwick/HOStringSense-for-Xcode

7:cocoapods-xcode-plugin  pod相关的操作可以在xcode菜单进行

地址:https://github.com/kattrali/cocoapods-xcode-plugin

8:switch枚举的时候会自动生成代码

地址:https://github.com/stefanceriu/SCXcodeSwitchExpander

9:Git中关于各个语言的gitignore

地址:https://github.com/github/gitignore

10:FLEX(Flipboard Explorer)是Flipboard官方发布的一组专门用于iOS开发的应用内调试工具

地址:https://github.com/Flipboard/FLEX

11:ponyDebugger是一个远程调试工具包,通过使用Chrome开发者工具来调试iOS应用的网络流量和数据存储

地址:https://github.com/square/PonyDebugger

12: OC编码风格规范

地址:https://github.com/NYTimes/objective-c-style-guide

13:FBMemoryProfiler:Facebook出品的一个实时监测内存使用的库。相比于Xcode自带的Instruments

地址:https://github.com/facebook/FBMemoryProfiler

14:app卡顿问题检测–KMCGeigerCounter(实例可以网上搜索)

地址:https://github.com/kconner/KMCGeigerCounter/

15:生成类的关系图KSHObjcUML

地址:https://github.com/kimsungwhee/KSHObjcUML

16:realm-cocoa实体映射数据库,有自个的数据库(可以替换SQLITE,速度比较快)

地址:https://github.com/realm/realm-cocoa

17:创建文档API,可以快速让APP先调用,并行开发

地址:https://apiary.io/

18:直接查看虚拟器上的沙盒路径simpholders

地址:http://www.maczapp.com/simpholders

19:FastStub实现了类似的功能,能自动解析出某个类头文件,父类,所有protocol里面还没有被实现的方法(ctrl+cmd+k)

地址:https://github.com/music4kid/FastStub-Xcode

三:第三方插件

1:基于响应式编程思想的oc

地址:https://github.com/ReactiveCocoa/ReactiveCocoa

2:hud提示框

地址:https://github.com/jdg/MBProgressHUD

3:XML/HTML解析

地址:https://github.com/topfunky/hpple

4:有文字输入时,能根据键盘是否弹出来调整自身显示内容的位置

地址:https://github.com/michaeltyson/TPKeyboardAvoiding

5:状态栏提示框

地址:https://github.com/jaydee3/JDStatusBarNotification

6:block工具包。将很多需要用delegate实现的方法整合成了block的形式

地址:https://github.com/zwaldowski/BlocksKit

7:图片加载

地址:https://github.com/rs/SDWebImage

8:正则表达式

地址:https://github.com/wezm/RegexKitLite

9:Masonry代码布局

地址:https://github.com/SnapKit/Masonry

10:弹出窗

地址:https://github.com/sberrevoets/SDCAlertView

11:Button的样式

地址:https://github.com/mattlawer/BButton

12:验证网络连接状态

地址:https://github.com/tonymillion/Reachability

13:自动计算表格行高

地址:https://github.com/forkingdog/UITableView-FDTemplateLayoutCell

14:关键帧基础动画框架,如动画效果的启动页

地址:https://github.com/IFTTT/JazzHands

15:iOS快速简单集成国内三大平台分享

地址:https://github.com/xumeng/XMShareModule

16:五项能力值展示的五边形

地址:https://github.com/dsxNiubility/SXFiveScoreShow

17:自动识别网址号码邮箱和表情的label

地址:https://github.com/molon/MLEmojiLabel

18:IM对话功能的封装

地址:https://github.com/ZhipingYang/UUChatTableView

19:字典转模型框架

地址:https://github.com/CoderMJLee/MJExtension

20:下拉上拉刷数据

地址:https://github.com/CoderMJLee/MJRefresh

21:表格行左右划动菜单

地址:https://github.com/MortimerGoro/MGSwipeTableCell

22:图文混搭

地址:https://github.com/zhouande/TLAttributedLabel

23:可以简单展示在UINavigationBar下方,类似Music app的播放列表视图,弹出菜单视图

地址:https://github.com/DrummerB/BFNavigationBarDrawer

24:比如筛选、模糊、优化、蒙版、调整大小、旋转以及保存等等。同时还提供了一个UIImageView子类从URL异步加载图片,并在下载完毕时展示图片。

地址:https://github.com/Nyx0uf/NYXImagesKit

25:底部TabBar

地址:https://github.com/robbdimitrov/RDVTabBarController

26:表情面版

地址:https://github.com/ayushgoel/AGEmojiKeyboard

27:记录框架

地址:https://github.com/CocoaLumberjack/CocoaLumberjack

28:IOS与JavaScript交互

地址:https://github.com/marcuswestin/WebViewJavascriptBridge

29:图表统计展示

地址:https://github.com/kevinzhow/PNChart(或https://github.com/danielgindi/ios-charts)

30:appStore评分

地址:https://github.com/arashpayan/appirater

31:iOS-Categories扩展类大全

地址:https://github.com/shaojiankui/IOS-Categories

32:扫描二维码,仿微信效果,带有扫描条

地址:https://github.com/JxbSir/JxbScanQR

33:动效弹出视图(弹出窗里面为文字,可以定义弹出的方向,及显示的时间)–AMPopTip

地址:https://github.com/andreamazz/AMPopTip

34:基于Masonry自动计算行高扩展

地址:https://github.com/632840804/HYBMasonryAutoCellHeight

35:模仿新浪微博弹出菜单

地址:https://github.com/wwdc14/HyPopMenuView

36:搜索历史标签

地址:https://github.com/zhiwupei/SearchHistory

37:快速集成新手引导的类库

地址:https://github.com/StrongX/XSportLight

38:设置页面的封装

地址:https://github.com/renzifeng/ZFSetting

39:带箭头的弹出视图插件

地址:https://github.com/xiekw2010/DXPopover

40:下拉菜单插件

地址:https://github.com/dopcn/DOPDropDownMenu/

41:表格空白提示插件

地址:https://github.com/dzenbot/DZNEmptyDataSet

42:给任意UIView视图四条边框加上阴影,可以自定义阴影的颜色、粗细程度、透明程度以及位置(上下左右边框)

地址:https://github.com/Seitk/UIView-Shadow-Maker

43:不错的日期时间插件

地址:https://github.com/CoderXL/UUDatePicker

44:底部弹出选择

地址:https://github.com/skywinder/ActionSheetPicker-3.0

45:比较不错的引导页面插件

地址:https://github.com/ealeksandrov/EAIntroView

46:两个APP跳转的插件

地址:https://github.com/usebutton/DeepLinkKit

47:本地存取NSUserDefaults插件

地址:https://github.com/gangverk/GVUserDefaults

48:NSArray和NSDictionary关于LINQ的操作方式,封装一些常用的操作

地址:https://github.com/ColinEberhardt/LinqToObjectiveC

49:可以监控网络请求的内容

地址:https://github.com/coderyi/NetworkEye

50:时间帮助插件,可以快速获取时间,比较,增加等操作

地址:https://github.com/MatthewYork/DateTools

51:不错的链式动作

地址:https://github.com/jhurray/JHChainableAnimations

52:弹出层视图,背景效果(可以自定义视图的内容)

地址:https://github.com/HJaycee/JCAlertView

53:圆形进度条的显示,中间可显示值

地址:https://github.com/mdinacci/MDRadialProgress

54:很帅的数据加载动画(可以用于数据列表加载的展现)

地址:https://github.com/NghiaTranUIT/FeSpinner

55:一个开源的AFnetworking上层的封装(猿题库等运用)

地址:https://github.com/yuantiku/YTKNetwork

56:CBStoreHouseRefreshControl:一个效果很酷炫的下拉刷新控件

地址:https://github.com/coolbeet/CBStoreHouseRefreshControl

57:AFNetworking-RACExtensions:针对ReactiveCocoa的AF封装

地址:https://github.com/CodaFi/AFNetworking-RACExtensions

58:模糊效果(毛玻璃)

地址:https://github.com/nicklockwood/FXBlurView

59:UITableView展开效果的插件

地址:https://github.com/sakkaras/SKSTableView

60:ZIP压缩及解压插件ZipArchive

地址:https://github.com/ZipArchive/ZipArchive

61:自定义UIAlertView

地址:https://github.com/lmcd/LMAlertView

62:Facebook开源的动画库Pop

地址:https://github.com/facebook/pop

63:关于使用facebook动画库的实例集合

地址:https://github.com/schneiderandre/popping

64:iOS应用视图上添加简单闪烁效果Shimmer

地址:https://github.com/facebook/Shimmer

65:ios数据持久化插件,使得Core Data使用起来更加的便捷容易

地址:https://github.com/magicalpanda/MagicalRecord

66:创建缩合的iOS应用程序标题栏

地址:https://github.com/bryankeller/BLKFlexibleHeightBar

67:PDF阅读器核心库

地址:https://github.com/vfr/Reader

68:STPopup使弹出框也有UINavigationController的效果

地址:https://github.com/kevin0571/STPopup

69:基于核心音频,有助于进行实时,低延迟音频处理和可视化的iOS和OSX音频可视化框架

地址:https://github.com/syedhali/EZAudio

70:一个不错的弹出Sheet,可以前进跟后退,适合多个页面

地址:https://github.com/m1entus/MZFormSheetController

71:Aspect库是对面向切面编程的实现,里面封装了Runtime的方法

地址:https://github.com/steipete/Aspects

72:一个不错在无输入源的输入框,如UITableViewCell等

地址:https://github.com/slackhq/SlackTextViewController

73:小红点插件,用于提示未读效果

地址:https://github.com/weng1250/WZLBadge

74:不错的照片选择器,视频选择器,支持单多选

地址:https://github.com/mwaterfall/MWPhotoBrowser

75:含10多种的转场动画效果

地址:https://github.com/ColinEberhardt/VCTransitionsLibrary

76:左右菜单显示(类似QQ导航)

地址:https://github.com/romaonthego/RESideMenu

77:很赞的等待指示动画(比系统自带的帅)

地址:https://github.com/ninjaprox/DGActivityIndicatorView

78:KVOController一个简单安全的KVO(Key-value Observing,键-值观察)工具,提供简单方便、线程安全的API, Facebook的开源项目之一

地址:https://github.com/facebook/KVOController

79:FormatterKit收集了很多构思优秀的NSFormatter子类

地址:https://github.com/mattt/FormatterKit

80:自定义的UIPageControl(可以设置每个的样式)

地址:https://github.com/Spaceman-Labs/SMPageControl

81:使用NJKWebViewProgress做webview进度条(解决先前无法获得进度的问题)

地址:https://github.com/ninjinkun/NJKWebViewProgress

82:修改NavigationBar的显示效果

地址:https://github.com/ltebean/LTNavigationBar/

83:FCUUID获得设备号的替代方式

地址:https://github.com/fabiocaccamo/FCUUID

84:多主题色或者白天黑夜模式的运用

地址:https://github.com/Draveness/DKNightVersion

85:GPUImage是一个基于GPU图像和视频处理的开源框架,提供各种各样的图像处理滤镜

地址:https://github.com/BradLarson/GPUImage

86:YY图片加载插件,可以支持动态,网络本地,渐进式图片加载等

地址:https://github.com/ibireme/YYWebImage

87:封装后的蓝牙帮助库

地址:https://github.com/coolnameismy/BabyBluetooth

88:一个很通用的需求就是引导教程

地址:https://github.com/bubudrc/MPCoachMarks

89:基于MPMoviePlayerController播放器KRVideoPlayer

地址:https://github.com/36Kr-Mobile/KRVideoPlayer

90:UICollection左对齐跟右对齐

地址:https://github.com/mokagio/UICollectionViewLeftAlignedLayout

地址:https://github.com/mokagio/UICollectionViewRightAlignedLayout

91:自定义弹出对话窗,类似系统又可以自定义视图DQAlertView或MMPopupView

地址:https://github.com/dinhquan/DQAlertView

地址:https://github.com/adad184/MMPopupView

92:输入框在焦点获得时会有一个小标题JVFloatLabeledTextField

地址:https://github.com/jverdi/JVFloatLabeledTextField

93:针对一些UI进行显示优化,可以设置一些不同的背景色等

地址:https://github.com/Grouper/FlatUIKit

94:色彩插件,如果没有设计师又想一些漂亮的色彩就可以运用Chameleon

地址:https://github.com/ViccAlexander/Chameleon

95:两个不错的侧边栏显示插件ECSlidingViewController,SWRevealViewController

地址:https://github.com/ECSlidingViewController/

ECSlidingViewController

地址:https://github.com/John-Lluch/SWRevealViewController

96:各式各样的进度条,可以放在不同地方NAV或者图片或者扇形M13ProgressSuite

地址:https://github.com/Marxon13/M13ProgressSuite

97:拉动UITableView时CELL有一摇动的效果AMWaveTransition

地址:https://github.com/andreamazz/AMWaveTransition

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速