分类
dev

Module模块化iOS开发的应用再回顾

Pre

2016年在华奥时, 在当时的项目需求下, 萌生了模块化设计的想法. 而思考如何划分各模块、各组件时, 写了篇文章: Module化的 iOS应用开发. 当时更多的是在思考划分界限, 然后用私有Cocoapods库进行组织的初实践. 而后来这个办法得到了实际使用的良好反馈, 我又将它逐步打磨. 形成了Core库(github)的设计. 可能是觉得和之前的文章内容并无实质上区别, 也就没有单独写一篇来记录. 现在想想, 其实这是前文设计的一个更完备的形式.

设计

如前文提到的, 使用私有的Cocoapods进行模块组合管理, 为了解耦关联, 这里采用Core核心库的形式:

graph TB
subgraph LYCore

  subgraph id31[Third-party Libs<br>]
  id311[AFNetworking]
  id312[LYCategory]
  id313[Realm]
  id314[...etc]
  id311---|sibling| id312
  id312---|sibling| id313
  id313---|sibling| id314
  end

  subgraph id32[Implementation<br>]
  id321[Networking Layer/API wrapper]
  id322[Persistence Layer/Database wrapper]
  id323[Configuration Layer]
  id324[Class Base]
  id321---|sibling| id322
  id322---|sibling| id323
  id323---|sibling| id324
  end

  subgraph id33[Resource<br>]
  id331[Bundle wrapper]
  id332[Image]
  id333[Font]
  id334[Sound]
  id335[...etc]
  id331---|sibling| id332
  id332---|sibling| id333
  id333---|sibling| id334
  id334---|sibling| id335
  end

end

核心库的实现中,

  • 持久化层, 数据库访问封装, 文件读写封装;
  • 配置层, 配置文件的访问封装;
  • 网络层, 包含了Server API的基础访问封装, 并可通过配置文件初始化;
  • 基类, 包含各种常用类的定义;

这样基于Core(核心)库, 可开始构建各个实际的功能模块(Module).

Module也以Cocoapods Library的形式创建, podspec里注明依赖于Core库.
构建在Core之上的Module, 可通过Core库访问Server API、了解当前用户鉴权状态、读写数据库、获取&调整配置等.
无需依赖其他模块.

App则最终以工程的形式创建, 通过Podfile选择所需的模块们(Modules).
这和使用其他的第三方库一样, 没什么区别.

整体架构大致如图:

graph TB
  id1["Module: LYCore<br>(git repo | pod lib)"]
  id11["Module: A<br>(git repo | pod lib)"]
  id12["Module: B<br>(git repo | pod lib)"]
  id13["Module: C<br>(git repo | pod lib)"]
  id14["Module: D<br>(git repo | pod lib)"]
  id15["Module: E<br>(git repo | pod lib)"]
  id21["App: 1<br>(git repo | project)"]
  id22["App: 2<br>(git repo | project)"]
  id1-->|podspec| id11
  id1 -->|podspec| id12
  id1 -->|podspec| id13
  id1 -->|podspec| id14
  id1 -->|podspec| id15
  id11 -->|podfile| id21
  id12 -->|podfile| id21
  id13 -->|podfile| id21
  id12 -->|podfile| id22
  id13 -->|podfile| id22
  id14 -->|podfile| id22
  id15 -->|podfile| id22

Author

Luo Yuluoyu@luoyu.space

分类
dev

About Cocoapods

关于安装Cocoapods

Cocoapods(后简称为pod)是一个Ruby程序, 当然可以在Gem里找到并安装.

但如果我们系统里有统一的包管理器Homebrew(后简称brew), 更应该经由它来安装, 这样也便于统一的管理版本, 以避免不同的包在不同的程序管理下的混乱局面.

通过brew安装pod就很简单:

brew install cocoapods

升级Cocoapods

随着Xcode及SDK的不断升级, Cocoapods也在跟着不断升级以适应项目生成.

所以我们一定要及时更新pod版本, 以免在Xcode升级后, 生成的xcodeprojpod有兼容问题.

如上所述, 通过brew安装的包, 也应该通过brew来管理版本, 升级也很简单:

# 先更新下brew的formula信息:
brew update
# 如果Cocoapods有可用更新上面的命令结果会展示出来.

# 想查看全部可更新的包:
brew outdated

# 更新Cocoapods
brew upgrade cocoapods

CDN

新的pod(1.9.x)已支持CDN加速, 不过目前也没用出速度区别来~

可以看到的改变在~/.cocoapods/repos/目录下,

  • 旧的 master仓库/trunk仓库 已经没了, 现在默认仓库名为cocoapods.
  • 新增一个trunk文件夹, 类别为CDN (https://cdn.cocoapods.org/), 此目录非git仓库.

实际使用下, pod install会从CDN读取以确定安装的库的版本.

也就是说, 库版本的确定现在的路径是:

Podfile.lock > CDN > cocoapods repo

如需更新必须使用pod update.

利用指定repo来加速

指定repo本是可以添加私有Spec仓库的.

例如我曾在某项目里用到:

Podfile:

source 'https://github.com/CocoaPods/Specs.git'
source 'https://github.com/blodely/LYSpecs.git'
source 'https://e.g.some.company.git.server/PrivateSpecs.git'

来指定除了官方仓库外, 还有自己的LYSpecs仓库(里面有一些未推到官方的libs), 和公司的私有库(包含一些模块化的库, 但仅限公司内部访问).

source就可以指定多来源.

pod仓库在GitHub, 对于国内用户来说访问速度不是特别友好, 特别是Spec仓库目录及文件众多, 克隆和拉取都很慢, 容易因网络波动断开.

这样我们就可以用一些国内的Cocoapods spec的镜像来作为源.

应用起来很简单:

# 在Podfile首行加上你所想用的镜像地址

# 清华源
source 'https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git' 

# 或者码云的源
source 'https://gitee.com/mirrors/CocoaPods-Specs.git'

# 或者其他

注意找信得过源哦!~

推荐没什么大问题的情况下, 大家都使用官方源.

关于Repo仓库

用过pod searchpod repo add, 可能会找到在路径~/.cocoapods/repos/下的一些仓库.

它们事实上就是一个git管理的仓库, 包含了所有被提上去的pod库的spec等信息.

所以当我们对一个项目的Podfile运行pod install命令时, 它会知道每一个pod库应该从哪去获取.

search的索引

pod的spec仓库如此复杂而缓慢, 搜索如果是直接从中进行, 那效率会太低.

所以pod的做法是, 根据仓库创建一个用于搜索的索引文件(index), 然后使用索引来搜索(pod search).

这个文件位于~/Library/Caches/CocoaPods/search_index.json.

当首次克隆完spec仓库后执行搜索时, 或是添加了新的spec仓库后执行搜索时, 它都会出现一个Creating search index for spec repo 'xxx'..的等待过程.

如若遇到索引文件不正确的情况无法search, 可以删除该index, 让pod重新生成一个, 来修复该问题.

Author

Luo Yu

luoyu@luoyu.space

Wednesday, July 8, 2020

分类
stuff

iOS App Store Review Guidelines 探讨

首先, 这里是App Store Review Guidelines的官网链接.
啥都要以它为准, (哪怕是觉得他们错了要申诉).

“大礼包”

最近才从前公司组里同事那听来这个词, 有点有趣.
在网上看了看大家提的审核问题, 很快就发现了诸如“2.1大礼包”, “4.3大礼包”, “礼包5.0”等等有趣的叫法.
想必是些个坎吧.

2.1 App Completeness

程序完备性.
个人感觉这一块的问题应该算是可以比较容易解决的问题.
某种程度上, 是提交方自己没做好的.
按照指示修复问题即可.

2.3 Accurate Metadata

很常见的, 应用程序元数据不准确.
这里可见Apple的要求比较严格. (我碰到的审核问题大部分都在这一块).

列举常见的此类问题:
- screenshot: 目前对于手机应用, 必传的图有iPhone X/iPhone 8 Plus的尺寸图; 需要注意的是, 图中若出现iPhone, 则需反应对应图片所指代的iPhone(也就是说iPhoneX的图里的手机必须是iPhone X, iPhone Plus里则是普通iPhone).
- 应用介绍内容和应用程序不一致; 不要写太宽泛就好; 需要注意的是, 一些诸如医疗、慈善等相关的内容, 需要发布公司/单位即该内容的提供方, 要不然是肯定不会通过的.
- 搜索关键字;

4.3 Spam

导引上说“Don’t create multiple Bundle IDs of the same app.”
看来这条是重复包改名提交的行为了.
这个我可没做过.
不过试想了一下, 如果真有这种需求, 改动一点再提交吧, 对于有开发人员的情况, 这应该不是什么大问题.
如果只是买了别人的应用代码就想提交的话..恐怕会遇到此问题.

相关审核规则:
4.3.0 - Are a duplicate of another app or are conspicuously similar to another app

IAP应用内购相关

积分or类似积分形式, 数字消耗品, App内消耗品等类似形式的购买物, 都应走In-App Purchase(应用内购).

列举相关:
3.1.1 - Use payment mechanisms other than in-app purchase to unlock features or functionality in the app

隐藏功能相关

若Apple审核以某种手段检测or怀疑提交审核的应用包含隐藏功能, 可能列举如下条款:

1.1.6 - Include false information, features, or misleading metadata.
2.3.0 - Undergo significant concept changes after approval
2.3.1 - Have hidden or undocumented features, including hidden "switches" that redirect to a gambling or lottery website

这里说得很明确了, 隐藏功能, 审核通过后会出现重大功能变更...
马甲包的问题在此.

Legal 法律相关问题

基本指明了, 若要提供相关服务, 必须是具有该资质的机构/公司/单位提交应用.

5.2.1 - Were not submitted by the legal entity that owns and is responsible for offering any services provided by the app
5.2.3 - Facilitate illegal file sharing or include the ability to save, convert, or download media from third party sources without explicit authorization from those sources
5.3.4 - Do not have the necessary licensing and permissions for all the locations where the app is used

借贷问题相关:
3.2.1 - Do not come from the financial institution performing the loan services
具有资质的机构才能提交借贷相关功能的应用.

Author

骆昱(Luo Yu)

Email: indie.luo@gmail.com

Version

1.0.0, Thursday, August 16, 2018

分类
stuff

笔记: WWDC 2016 Session 805 Iterative UI Design

前面

最近在翻看WWDC视频.
这个属于原型设计块的内容, 以前也确实没有发掘看看.
觉得还不错, 有很多更Apple风格的思路. 留点笔记吧.

笔记

805所说的迭代UI设计, 更多的是在讲如何从零开始设计一个App.
迭代的, 是产品设计的实现过程.

围绕一些问题, 可以来梳理思路:

  1. What are we making?
  2. Who is it for?
  3. Does it actually work?
  4. And did we get it right?

Identify the features that matter most to the people who will use your app,
and features that serve your own goals for the app it self.
In order to determine what your app should do.

还大字说明了一件感觉很多“产品经理”应该好好看看的--

You ≠ User

你不是用户.

Designing for yourself distracts you from what matters most to everyone else.

诸多产品经理喜欢用自己的习惯, 套上“用户”如何如何想, “用户”如何如何觉得这样的外衣, 来解读需求.
应该注意注意啦.

视频里还演示了用Keynote来画UI的过程, 并归纳了一下:
1. Use screenshots as references;
2. Draw some squares and lines;
3. Zoom in and out a lot (to make sure that they were pixel perfect);
4. Use believable content.

设计完一个界面后, 再继续延展.
因为一屏界面不是一个App, 需要完善workflow.

基本原则还是:

Started with what I knew and then I evaluated and iterated on all my designs until I ended up with something I was happy with.

整个过程就是805所在提的, iterative design, 迭代设计.

实际看来, 他们的操作, 有多设计, 多比较, 比我日常看到的有更多的互动.
而不是一个人盯着一屏幕的工具, 和别人家的产品, 埋头~~抄抄抄~~画画画.

Author

骆昱(Luo Yu, indie.luo@gmail.com)
Tuesday, August 14, 2018

分类
dev

iOS 11 | Natural Language Processing

CoreML

iOS 11推出的新framework - CoreML, ML即Machine Learning.

官方给出的架构如下图:

CoreML-framework-arc

如图可见, 该框的几个实现包括Vision, 还有NLP.

NLP (Natural Language Processing)

常有功能:

  • Language Identification
  • Named Entity Recognition

架构:

NLP-arch

这么一来, 封装后使用变得简单.

NSLinguisticTagger

分类
dev

Code Review (ObjC for iOS project)

Review时, 找寻的目标..

假定项目/公司既有代码规范, coder遵从or不遵从规范都是显而易见的.

故不评审代码样式/风格/规范.

找寻的目标, 应该是潜在bug和有性能问题的代码.

一些ObjC审查问题

代码层面的基础问题:

  1. 内存泄漏; 野指针问题.
  2. 线程安全.
  3. 循环依赖.
  4. 集合类型“越界”可能.
  5. 条件判断等的边界考虑.

代码组织设计上的问题:

  1. 类的单一职责原则;
  2. 方法设计, 与其他的耦合关系;
  3. 模块的设计问题;
  4. 算法类方法的瓶颈审查.
分类
dev

界面拼接设计

拼接界面

这个需求产生的最初原因,是部分不懂软件开发的人,在自认为懂软件开发的情况下,认为的理所当然的功能.

就是一个模块化/组件化的产品,就应该是像乐高积木一样,可以动态随意组合成应用.

功能是可以以某种形式存在的,但这里的灵活组合只能源于独立的设计,而非已有的功能.

而动态组合,也一定存在局限.

这些是需要先明确的.

设计

思路

需要拼接,自然就能想到将界面中的每一元素,独立成类似属性的视图,使他们能统一进行大小+位置+顺序的操作.

这样就是组合界面了.

而呈现这些视图的程序,则为每一个模块.

也就是说,如果导入一个模块A,它将同时提供一个入口视图(例如一个A按钮),可以配置 大小/位置/顺序.

配置文件也将包含这些属性:

模块排序,视图大小,原点位置.

也就是说,如果配置文件写得足够通用的话,可以做到跨平台使用.

例如统一使用XML格式编写配置. 亦或是直接完成一套Android平台的库.

应用

类似一些语言的桌面应用开发的“布局”方式,这里最终的实现也是有点类似的感觉.

但它更加平台化.

这里我将它应用为一个移动平台专门的界面构建方式.

先按照仅有由上往下的一种布局方式来设计实现.

然后对于手机平台,通常情况下,是横向占满屏幕的,或是以某个数字来均分宽度:

例如:

A 0 0 0 0 0
0 0 0 0 0 0
B 0 0 0 0 0
C 0 0 D 0 0
E 0 0 0 0 0
0 0 0 0 0 0

矩阵一排为44pi的话,第一个组件A即高88pi,B、C、D都高44pi, E高88pi.

而宽度A、B、E都占满(假设是最多可以等分为6块),C和D则各占3块.

当然,在项目中,宽度最小粒度应该也属于可配置的.

在列表的数据中,组件是以数组的形式存在,本身就具有顺序.

语言内部

  1. 组件 -> 模型类

  2. 配置文件 -> 模型类

  3. 配置文件内,应该包含有一个序列的组件.

  4. 配置文件模型可以直接在界面构建中方便的使用,以确定界面如何布局.

  5. 配置文件模型可以导入数据(import),从plist文件或者XML文件.

  6. 配置文件模型可以导出数据(export)到plist文件或者XML文件.

  7. 视图生成器 -> 工具类

其他工作

作为library打包整个功能库,即可方便被应用.

Author 作者

骆昱(Luo Yu

2017-02-17

分类
dev

Module化的 iOS应用开发

因工作需要,开始希望移动应用开发能走模块/组件式的过程,来提高功能的复用性,减少开发的时间,从而满足快速的产品输出需求。

需求的来源源自公司的新项目方向通常是与已有的项目存在部分类似的功能,又有自己独特的模块。

在此基础下,将功能尽量独立出来,做到不同项目导入+配置即可使用,除了减少开发、测试的工作,也可提高该功能的可维护性(修改一次代码,可以同时更新多个引用此功能的项目)。

难点在于模块式的iOS应用开发。

首先是解耦功能。

实际情况1

考虑到网络层一般已有AFNetworking/Alamofire这样的库,网络层通常是对应Server RESTAPI进行配合,做初步解析,区分API Error与Success,以便每个数据请求处理结果。

对于某些特定的情况,例如没有对OSS文件服务器接口进行包装的Server,文件上传的操作也是在App内做的情况下,这些操作也应该归纳到网络层的范围内。

这样下来,如果在Server Domain,API前缀,OSS鉴权信息等可配置的情况下,可以将该组件+网络库(如AFNetworking)独立出来,形成一个模块。

实际情况2

用户登录

包含用户的权限判定,与登录界面显示的触发;登录界面UI与输入交互;登录操作的网络请求,成功失败的处理等。

权限判断与界面触发都与其他界面里用户的操作相关联,但可行的是,判断本身都是与固有数据的操作,是外部对模块内的单向调用。

登录界面UI,无法确定,同一家公司的话,可能有一定的复用性,具体情况待定。

网络请求可以暴露出组件,或是可配置的请求地址,待定。

可见登录,是一个有部分独立性的模块。

实际情况3

注册

注册UI,无法确定,不同项目有不同的注册所需字段的需求;
注册步骤,无法确定,不同项目,注册的流程都可能不一样,有的追求简单快速,有的则有许些必要的信息需要录入并验证。

注册不应该做成模块,可复用性也很低。

模块与项目引用的解决方案

首先,应该考虑的是Git与Git Submodule,似乎生来就是为项目模块化设定的。

好处有很多,依赖关系很明确,所见即所得,如何将模块添加到工程都是开发人员自己决定的。

而对于工程本身来说,其实还是一个整体。

编译输出全在一个二进制文件里。

其次,使用私有的Cocoapods进行配置管理。

思路大致如下:

分类
dev

iOS中 OCR光学识别的运用

在一些特定场景下我们需要利用iPhone(or any iOS devices)的摄像头来进行光学识别(OCR-Optical Character Recognition),本文即是对此方向的研究。

版权所有,如转载请先联系indie.luo@gmail.com。


一些轮子:

  • TesseractOCR

Tesseract OCR iOS | 开源的OCR框架,在其GitHub页面上可发现仍然持续更新中。
它是Tesseract框架的一个iOS实现。

关于当前(Jul 19, 2016)TesseractOCR-iOS的一些注意事项:
使用的Tesseract库版本为 3.03-rc1。所以在Github上找到的3.04语言训练文件不能用会报错。
实测可以使用旧版3.02版本的语言训练文件。(同样的问题出现在chi_sim, jp等语言上)。

Github的issues里作者有展开讨论更新3.04的问题,因为官版tag打的位置有bug,所以现在最好还是等下一个更新版。

  • GPUImage

GPUImage | 不用多说,Github上闻名的几个iOS项目之一。一考虑到本项目需要一些摄像头控制,一些图片的调整,就想到GPUImage会派上用场。

  • OpenCV-iOS

利用机器视觉,识别文档边缘,判断方向,识别照片的视角扭曲,对应作出修改等。

  • ImageMagick

ImageMagick | 对图片的进一步修改/编辑操作,可以使用这个命令行版的“Ps”工具。例如场景:需要对有倾斜拍摄的图片进行视角扭曲,可以很好的利用该工具提供的Perspective Distortion(从平时使用Ps做Perspective Crop裁剪得来灵感)。


定义存储数据类型

当前研究是做ID识别,先定义一个存储ID数据的对象。

满足以下要求:

  • 实现 NSCoding和NSCopying

  • 字段 ID号码,姓名,民族,住址,有效期,签发机关

  • 比较方法 -isEqualToID:

  • 描述方法 -description


组织问题

识别是基于整张图片的,所以即使正确识别出所有文字,引擎也无法分辨谁是谁。
所以如果希望区分内容,请在识别之前,对图片进去分割。

分类
dev

iOS Project with Dependency Manager

Notice: 当前Apple为Swift正在准备一套包管理器,详情参见Github

依赖管理器 Dependency Manager 和 包管理器 Package Manager 

Cocoapods 依赖管理器 Dependency Manager
cocoapods.org/
官方简介:

CocoaPods is a dependency manager for Swift and Objective-C Cocoa projects. It has over eighteen thousand libraries and can help you scale your projects elegantly.

官方安装是通过gem源进行的。

但是有以下几点缺点:
gem install需要sudo权限。
默认的gem源https://rubygem.org/国内环境无法访问。淘宝提供的gem镜像也并不稳定。

使用Homebrew包管理器安装

关于Homebrew:(如果已用,请跳过此节)
brew.sh
官方的一点介绍:

Homebrew installs the stuff you need that Apple didn’t.

Homebrew installs packages to their own directory and then symlinks their files into /usr/local.

Homebrew won’t install files outside its prefix, and you can place a Homebrew installation wherever you like.

Trivially create your own Homebrew packages.

It's all git and ruby underneath, so hack away with the knowledge that you can easily revert your modifications and merge upstream updates.

Homebrew formulae are simple Ruby scripts

Homebrew complements OS X. Install your gems with gem, and their dependencies with brew.

强烈推荐Mac环境下使用Homebrew包管理器,而非MacPorts。
Homebrew已有的formula参见:
https://github.com/Homebrew/homebrew-core/tree/master/Formula

安装Homebrew:

Terminal(终端)中粘贴并运行此命令:
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

以后需要查找包,直接使用搜索命令:
brew search …

安装包:
brew install …

检查Homebrew状态:
brew doctor

这里我们将使用Homebrew来安装Cocoapods。
brew search cocoapods
可以看到结果里有Cocoapods
那直接brew install cocoapods
等待安装完成~

测试一下Cocoapods是否安装成功,运行命令:
pod
返回结果里有pod正确的使用方法解释,看来是安装成功了。
以后pod升级也不用再sudo gem install了。

使用官方gem安装方法的请注意了:
Cocoapods安装需要sudo权限。但是平时pod时一定不要用sudo。
特别是第一次初始化pod repos的时候,如果使用sudo,将会导致一系列问题,(其实都是权限不对导致)。

使用brew install的,本身不用sudo,不用担心这个问题。

关于Spec repos
初次安装Cocoapods将会克隆一份spec repository到本地。
因为该项目又大文件夹又多,可能容易中断。

实际Spec项目就在Github,链接:
https://github.com/CocoaPods/Specs.git
可以git clone该项目到本地,或者下载zip文件的方式获取它。

将整个repo命名成master,然后放到~/.cocoapods/repos/下即可。

这个时候,再跑一遍命令以完成Cocoapods的初始化:
pod setup

来替代Spec仓库初始化命令的操作。

使用Cocoapods控制第三方库依赖

在Xcode Project目录下,运行pod init命令,将初始化一个Podfile文件。

向其中添加pod库即可。

修改完成后,运行pod install命令,将依据此Podfile生成工程 workspace,包含配置好的所有库。

命令都会输出应有的操作提示。

Where To Go

关于该依赖管理器,还有很多运用,比如自建私有的Pods仓库,本地引用,透过Git引用等。

骆昱
2016-07-05