首页 文章 精选 留言 我的

精选列表

搜索[网站开发],共10000篇文章
优秀的个人博客,低调大师

Android开发技术重要参考资料

只言片语 有的时候看不懂别人的代码,觉得自己笨;其实,你想多了,看不懂不是因为你蠢而是别人的代码写得烂;所以,别那么宽容别人却苛责自己。 参考资料 郭霖 way 爱哥 有心 胡凯 robin trinea 秋百万 时之沙 张兴业 黄俊东 短裤党 柳志超 四方城 litesuits Gracker 农民伯伯 云在千峰 Robin Hu FireOfStar 傲慢的上校 浪人的星空 nkmnkm的专栏 学习教程 技术前沿 技术周报 Android源码 开源项目分析 OpenGL ES教程 Pro Android教程 FFMPEG安装教程 Android中文翻译组 ButterKnife使用教程 Google官方培训课程 Android官方示例教程

优秀的个人博客,低调大师

【iOS 开发】SnapKit 是怎样炼成的

前言 这是对 Swift 布局框架 SnapKit 的源码的一点分析,尝试搞清,一个好的布局框架,背后都做了些什么。 介绍 SnapKit 中的一些类 ConstraintView 等同于 UIView ConstraintAttributes 用于构造约束关系的各种元素(上下左右等) ConstraintDescription 包含了包括 ConstraintAttributes 在内的各种与约束有关的元素,一个 ConstraintDescription 实例,就可以提供与一种约束有关的所有内容。 ConstraintMaker 构造约束关系的起点,提供了 <code>makeConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void)</code> 方法来为程序员提供了描述约束的空间,也可以通过 left right top bottom centerX centerY 等属性,去生成一个 ConstraintMakerExtendable 实例(见下面) ConstraintMakerExtendable(继承 ConstraintMakerRelatable) 提供 left right top bottom leading trailing edges size margins 等内容,用以产生一个 ConstraintMakerRelatable 类型的实例 ConstraintMakerRelatable 直接用于构造约束关系,也是常用方法 <code>equalTo(_ other: ConstraintRelatableTarget) -> ConstraintMakerEditable</code> 与 <code>equalToSuperview</code> 的来源。核心方法是 <code>relatedTo(_ other: ConstraintRelatableTarget, relation: ConstraintRelation, file: String, line: UInt) -> ConstraintMakerEditable</code>,返回 ConstraintMakerEditable 类型的实例 ConstraintMakerEditable(继承 ConstraintMakerPriortizable) 在设定约束的宽度、高度以及偏移的时候,提供相应的加减乘除方法,返回 ConstraintMakerPriortizable 类型的实例 ConstraintMakerPriortizable(继承 ConstraintMakerFinalizable) 提供方法来设置约束的 priority,返回 ConstraintMakerFinalizable 类型的实例 ConstraintMakerFinalizable 一个只有一个类型为 ConstraintDescription 的属性的类,正如它的类名,有一个 ConstraintMakerFinalizable 实例,就得到了对于一个约束的完整描述。 至此,我们已经知道 SnapKit 是靠什么来确定了三个东西: 谁在做约束(ConstraintView) 怎么做约束(ConstraintMaker) 约束是什么(ConstraintDescription) let aView = UIView() aView.snp.makeConstraints({ make in make.width.equalToSuperview().dividedBy(2).priority(100) }) 当我们写下这样的语句时,先忽略掉 <code>snp</code> 是什么不管,里面设定 aView 的宽度为它的父视图的一半的这行约束语句,执行了这样的逻辑: ConstraintMaker 提供 <code>makeConstraints</code> 方法来让我们写约束的同时,开始维护了一个 ConstraintDescription 数组,叫 <code>descriptions</code> make 本身是 ConstraintMaker 类型的 在我们写下 <code>.width</code> 时,<code>descriptions</code> 数组第一次加入内容(<code>self.description</code>),同时我们用这个内容生成了一个 ConstraintMakerRelatable 实例 在我们写下 <code>.equalToSuperview()</code> 时,上一步中的内容(<code>self.description</code>)继续添加信息,同时我们用它生成了一个 ConstraintMakerEditable 实例 之后的 <code>.dividedBy(2).priority(100)</code> 使得之前的 ConstraintMakerEditable 实例变成了一个 ConstraintMakerFinalizable 实例,这个实例的 description 属性的类型是 ConstraintDescription,它包含了我们所描述的全部内容。但由于 ConstraintMakerEditable 本身就继承自 ConstraintMakerFinalizable,所以 <code>.dividedBy(2).priority(100)</code> 这一部分即便不写,这条语句在语法上也已经完成。 做个总结:到这里我们发现 ConstraintMaker 以及和它相关的类,构造了一套 DSL 来让我们可以轻松地写出约束语句,而这些语句把信息都放到了一个 ConstraintDescription 实例(<code>self.description</code>)里面,但我们仍然不知道它是如何以 UIKit 里面的 NSLayoutConstraint 的形式作用的。 snp 是什么 SnapKit 里面存在这样一些东西: <code>public protocol ConstraintDSL {}</code> <code>public protocol ConstraintBasicAttributesDSL : ConstraintDSL {}</code> <code>public protocol ConstraintAttributesDSL : ConstraintBasicAttributesDSL {}</code> <code>public struct ConstraintViewDSL: ConstraintAttributesDSL {}</code> 上面我们知道了 <code>aView</code> 作为一个 UIView,它同时也就是一个 ConstraintView,ConstraintView 有一个 snp 的属性,这给我们提供了入口来通过 SnapKit 给任意的 UIView 或 AppKit 里面的 NSView 通过 <code>.snp</code> 这样的语法来写约束。 这个 snp 属性的类型就是结构体 ConstraintViewDSL 一看就是面向协议的写法,通过一个个的 extension 来给 protocol 添加功能,最后用 struct 实现出来,就有了 snp 这个属性。 let topView = UIView() let centerView = UIView() centerView.snp.makeConstraints({ make in make.top.equalTo(topView.snp.bottom).offset(16) }) 这段代码展现了 snp 的两个作用: snp 有 left top right bottom edges size 等一大堆属性,这些属性的类型是 ConstraintItem,这是用于构造约束位置关系的 snp 作为 ConstraintViewDSL,有 <code>prepareConstraints</code> <code>makeConstraints</code> <code>remakeConstraints</code> <code>updateConstraints</code> <code>removeConstraints</code> 等函数,我们最常用的是 <code>makeConstraints</code> ,传入一个 closure,在里面写约束关系。这里要注意,我们使用的 <code>makeConstraints</code> 方法来源于 ConstraintViewDSL,但真正实现了构造约束的其实是我们上文里面写的 ConstraintMaker 里面的 <code>makeConstraints</code> 方法,见图: 约束是如何作用的 到现在我们还是没说,从 snp 到 ConstraintMaker,再到 ConstraintMakerFinalizable 的 description 属性,到底哪里创建了 NSLayoutConstraint,答案其实在之前提过多次的 ConstraintMaker 里面 // public class ConstraintMaker internal static func makeConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) { let maker = ConstraintMaker(item: item) closure(maker) var constraints: [Constraint] = [] for description in maker.descriptions { guard let constraint = description.constraint else { continue } constraints.append(constraint) } for constraint in constraints { constraint.activateIfNeeded(updatingExisting: false) } } internal static func updateConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) { guard item.constraints.count > 0 else { self.makeConstraints(item: item, closure: closure) return } let maker = ConstraintMaker(item: item) closure(maker) var constraints: [Constraint] = [] for description in maker.descriptions { guard let constraint = description.constraint else { continue } constraints.append(constraint) } for constraint in constraints { constraint.activateIfNeeded(updatingExisting: true) } } 我们传入一个闭包来写约束关系时,这个闭包给叫做 maker 的 ConstraintMaker 实例写入了信息,遍历 maker 的 descriptions 之后(我们之前说一条约束语句最终得到一个 self.description,但往往会有多条约束,所以 ConstraintMakerFinalizable 里面的 self.description,在 ConstraintMaker 里被一个数组维护),我们得到了 Constraint 数组。 Constraint 这个类还没有介绍过,不过上面这个核心方法加上以前的内容,已经可以让我们猜出来,约束是怎么写出来的了: 其他内容补充 1 随便写了两句,展示一下各个方法传入的参数的类型,发现有各种 Target,貌似很复杂,不过点开之后发现是这种景象: 说白了就是因为 <code>equalTo:</code> 这个方法里面能传的参数类型比较多,手动来一个一个限制一下,我们看到 ConstraintRelatableTarget 这里可以放一些原生的可以代表数字的类型,外加四个自定义的 Constraint 类型。其他的 Target 协议也差不多是这种情况。 个人觉得这种做法还是挺值得学习的。 其他内容补充 2 SnapKit 里面用来表示位置主体的类其实不是 ConstraintView,而是 ConstraintItem 我们管这个“主体”叫 target,一个 target,再加上一个 ConstraintAttributes 实例,就可以组成一个 ConstraintItem。 有 attributes 属性很好理解,因为比如我们去做对齐,可以是 aView 的 top 和 bView 的 bottom 对齐,而不能是 aView 和 bView 对齐。但是为什么 target 的类型是 AnyObject 而不是 ConstraintView,即 UIView 或 NSView 呢? 在 ConstraintViewDSL 里面,target 确实是 ConstraintView 类型, 但在 ConstraintLayoutSupportDSL 里面,target 是 ConstraintLayoutSupport 类型, 在 ConstraintLayoutGuideDSL 里面,target 是 ConstraintLayoutGuide 类型 这部分就不具体解释了,想一探究竟的去看 LayoutConstraintItem.swift 这个文件吧。

优秀的个人博客,低调大师

docker 开发常用命令总结

Docker 常用命令总结,镜像下载,到docker容器创建,常用docker命令的 增删查 1.镜像下载,从hub.docker.com中下载最新版本的postgres docker pull postgres 2.首次启动一个容器,名称为--name docker-postgresql,把容器/root文件挂在到 ~/codehub下 -v ~/codehub:/root:ro,设置postgres密码为123456-e POSTGRES_PASSWORD=123456 docker run --name docker-postgresql -v ~/codehub:/root:ro -e POSTGRES_PASSWORD=123456 -d postgres 3.开启容器 docker start docker-postgresql 4.执行容器(已经开启的)并进入容器内部命令行 docker exec -it docker-postgresql bash 5.停止容器 docker stop docker-postgresql 6.查看所有容器(包含启动或者未启动的) docker ps -a 7.删除某个容器 docker rm docker-postgresql 8.查看正在运行的容器 docker ps 9.查看已经下载的镜像 docker images 10.查看容器详情 docker inspect docker-postgresql 11.私有仓库配置(客户端) 映射IP地址 vim /etc/hosts 192.168.0.160 reg.rzdocker.com sudo mkdir -p /etc/docker/certs.d/reg.rzdocker.com:5000 sudo scp -r ruizhi@192.168.0.160:/home/ruizhi/registry/certs/registry.crt /etc/docker/certs.d/reg.rzdocker.com:5000

优秀的个人博客,低调大师

lnmp团队开发环境docker环境搭建

docker-compose-nginx-php-mysql docker-compose+nginx+php+mysql+redis+elasticsearch fox.风 github库 https://github.com/foxiswho/docker-compose-nginx-php-mysql 喜欢的同学可自行下载 版本 php:5.6.x mysql:5.6.x nginx:latest elasticsearch:latest 说明 目前只针对MAC系统的安装,其他系统请自定修改 Volumes 和 Users 目录 安装方式 1.选择要安装的系统和版本 例如:mac系统 php5.6.x版本,进入mac-php56目录 cd mac-php56 2.docker-compose.yml配置更改 选择你需要的功能,不需要的用#号注释掉 3.生成镜像 这个时候 一定不能更换目录。 注意 如果你以前已经配置过一样的容器那么会自动覆盖容器 docker-compose up 时间比较长, 更新源都在国外,最好早晨拉取 nginx 配置文件位置:/etc/nginx/nginx.conf 来源:官方源 php 来源:官方源 php-fpm 配置文件及目录位置 /usr/local/etc/php-fpm.conf /usr/local/etc/php-fpm.d/www.conf /usr/local/etc/php-fpm.d 目录 php.ini 默认加载目录位置 /usr/local/etc/php/conf.d/ 目录 redis 来源:官方源 elasticsearch 来源:官方源 使用教程-MAC系统 新建目录 /Volumes/work/lanmps/vhost/ work:分区名称 lanmps:自定义目录 vhost:nginx 站点配置文件 复制 nginx/default.conf 到 /Volumes/work/lanmps/vhost/ 目录下 1.mac硬盘设置 mac 系统默认硬盘 不区分大小写, 如果需要区分请 按 http://blog.csdn.net/fenglailea/article/details/53083785 此链接中教程 重新分区。 建议分区,我这里是分区的 2.nginx 配置 进入nginx容器 docker exec -it compose_nginx_1 bash compose_nginx_1 容器名字可能不一样 注意 自动生成的名字是根据当前项目目录名字来的。 例如项目目录为mac-php56目录,那么生成容器前缀名字是macphp56_xxxx 配置nginx.conf vim /etc/nginx/nginx.conf 找到如下配置 include /etc/nginx/conf.d/*.conf; 修改为:(根据你自己分区名称置修改) include /Volumes/work/lanmps/vhost/*.conf; 保存和退出容器 3.php 配置 略 跟nginx类似 5.测试 在 /Volumes/work/lanmps/ 目录下 新建 index.php <?php phpinfo(); X.问题 X.1 权限问题 设置 可读写执行权限 chmod -R 777 /Volumes/work/lanmps

优秀的个人博客,低调大师

【iOS 开发】用泛型简化 instantiateViewController

使用 storyboard 的时候,我们经常会写出下面这样的代码,用来跳转到其他页面 if let editVC = self.storyboard?.instantiateViewController(withIdentifier: "EditVC") as? EditVC { self.navigationController?.pushViewController(editVC, animated: true) } 最多改成这样 guard let editVC = self.storyboard?.instantiateViewController(withIdentifier: "EditVC") as? EditVC else { return } 实在是太冗长了,简化第一步,或许我们可以直接将 <code>EditVC</code> 这个类型字符串化变成 <code>"EditVC"</code>,代码变成: guard let editVC = self.storyboard?.instantiateViewController(withIdentifier: String(describing: EditVC.self)) as? EditVC else { return } 嗯,更长了,但是既然 <code>EditVC</code> 使用了两次,这使得我们有机会把这个过程封装成一个函数,而 <code>EditVC</code> 是唯一需要传递的参数 func instantiateVC(vc:UIViewController) -> UIViewController? { let id = String(describing: vc.self) return storyboard?.instantiateViewController(withIdentifier: id) } // how to use guard let editVC = instantiateVC(vc: EditVC()) as? EditVC else { return } 封装之后依然尴尬: 因为我们不能确定每次都需要函数返回 <code>EditVC</code> ,所以只能用 <code>UIViewController</code> 当做返回值,这使得我们还需要再加上 <code>as? EditVC</code> 去做类型转换,相当于还是手动使用了两次 <code>EditVC</code> ,而不是一次 传入的参数是 <code>EditVC()</code> 而不是 <code>EditVC</code> ,看起来丑陋 一次解决两个问题的答案是:泛型! 我们在函数中限定泛型 <code>T</code> 为 <code>UIViewController</code> ,但 <code>T</code> 具体是我们的 App 中的哪个子类我们不去管,通过函数的参数来指定 T 的具体类型,随后确定出我们函数的返回值为那个我们指定的 <code>T</code> 最终结果: extension UIViewController { func instantiateVC<T: UIViewController>(type: T.Type) -> T? { let id = String(describing: T.self) return storyboard?.instantiateViewController(withIdentifier: id) as? T } } // how to use guard let editVC = instantiateVC(type: EditVC.self) else { return } 前后对比: // before guard let editVC = storyboard?.instantiateViewController(withIdentifier: "EditVC") as? EditVC else { return } // after guard let editVC = instantiateVC(type: EditVC.self) else { return } 提醒: 这里我假装这个函数回避掉了直接使用字符串去传入 <code>Storyboard ID</code> 的风险,但可以这么做的前提是,这里的 <code>EditVC</code> 到 <code>"EditVC"</code> 可以直接字符串化。 如果你也要这么做的话,至少要保证你的类名的字符串化的结果和你的 <code>Storyboard ID</code> 是有固定关联的。比如 <code>EditVC</code> 对应 <code>"editvc"</code> 或 <code>"EDITVC"</code> 或 <code>"editVC"</code> (这样你只要修改字母大小写就可以了),而不是 <code>"abc123"</code> 这种随便写的东西。

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册