分类
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

分类
stuff

笔记: ArchLinux环境

最近把旧电脑的坏硬盘换下来, 然后立马元气满满的样子. 就准备给它装个Linux来用.

另外好久没有更新,就把东西放上来好了.

准备安装U盘

从ArchLinux的官网下载最新的iso文件,文件很小.

然后用它制作启动U盘,因为在Mac中,就直接可以dd到U盘的设备.

启动安装环境

连接U盘,从U盘启动,进入安装环境.

先连上Wifi:

wifi-menu

从选择到配置都很简单.

也可随便ping个地址看连好了没.

准备硬盘空间了:

fdisk -l

列举了磁盘的情况.

我就用cfdisk分区了.

初次进,会让选择分区表类型,配合电脑这边就用的MBR.

创建一个primary分区,准备挂载/,标记上bootable;

因为主硬盘只有120G的SSD,准备在副硬盘上挂数据,这里就不多分区了;

然后准备一个swap分区.

然后write改变,退出 cfdisk.

接下来格式化硬盘,

mkfs.ext4 /dev/sda1
mkswap /dev/sda2

好了就可以激活swap,

swapon /dev/sda2

挂载分区:

mount /dev/sda1 /mnt

安装系统

pacstrap /mnt base
# 也可加上 base-devel

等它下载安装完以后,

创建fstab文件:

genfstab /mnt >> /mnt/etc/fstab

这就可以change-root了:

arch-chroot /mnt #/bin/bash

修改系统的配置

取消/etc/locale.gen文件里en_US.UTF-8的注释,

这个以后配置中文也要对应放开里面相关的项目,

然后激活它:

locale-gen

输出一个/etc/locale.conf文件:

echo 'LANG=en_US.UTF-8' > /etc/locale.conf

链接一下配置时区:

ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

同步时间:

hwclock --systohc # --utc

可以date试试看输出时间对不~

设置root密码:

passwd

设置hostname:

echo mr_luo_arch > /etc/hostname

启用dhcpcd:

systemctl enable dhcpcd

安装bootloader

先安装好grub:

pacman -S grub os-prober

安装grub引导,

grub-install /dev/sda

生成配置:

grub-mkconfig -o /boot/grub/grub.cfg

这里基础系统就装好了.

其他安装

不过我顺便装上桌面环境,最近觉得gnome3用着挺顺手的,

# 安装相关的包
pacman -Sy --nocomfirm gnome gnome-extra

# 启用gdm
systemctl enable gdm

这里的Gnome还少一个网络配置管理的工具,

顺道给它装上:

# 安装相关的包
pacman -S networkmanager

# 启用
systemctl enable NetworkManager

给加一个普通用户:

useradd -m -s /bin/bash NewUserName
# -m 创建home目录
# -s 设置默认shell

# 给它配置密码
passwd NewUserName

编辑/etc/sudoers文件,加上:

NewUserName ALL=(ALL) ALL

这样新用户可以用上sudo.

结束

退出change-root,重启就好啦~

exit
reboot

Author

骆昱

分类
dev

Docker in Production 笔记

In production

docker-workshop-thought-works

上周六参加了thoughtworks的docker workshop活动, 主要探讨了docker技术在生产环境应用的问题.

前面介绍了一下容器相关技术, 如Linux Container(lxc), 也介绍了namespace隔离等等.

还有docker的架构:

docker-architecture

然后又有部分常见的docker使用技术, 如docker compose, 使用compose.yml文件指定容器的创建, 以及整体管理等.

进阶

文件系统的挂载, 包括数据卷挂载(-v), 以及制作+使用数据容器的思路方向.

容器网络模型, host内的bridge, 跨host的overlay, 以及sandbox/endpoint定义.

docker-network

也扩展了一下安全性问题. (docker真的权限...太高了)

多主机部署于服务发现

Consul服务发现.

Registrator服务注册.

Docker Swarm集群.

日志/监控

docker logs的使用局限.

一点关于实际应用的思考

在docker的助力下,将每个服务,做成一个容器,然后跑在公司所有的主机上,这样的微服务架构想想就知道才是当下最合理的方式。

借助cluster解决方案,可以将公司的多服务器主机的资源合起来利用,并能更好的应对服务故障。

而容器微服务,在开发本地调试,一旦通过测试可以发布,发布的过程也是简单而不会出错。

构建好如上讲述的服务注册+发现,更能动态获取服务地址,自动完成服务之间的连接,才称得上是科学做法。

而服务状态监控,健康检查,日志收集处理,这些服务构建好,才能真的在出错时及时追溯问题,更能通过预警邮件及时知道问题。

一个产品环境,必须是科学专业的环境,而不是单单能运行就行。

分类
stuff

Rust-Lang Notes | Day 2

General

变量

变量默认是不可变immutable的.

let x = 5;
x = 6; // ERROR: re-assignment of immutable variable

mut关键字声明可变的变量.

let mut x = 5;
x = 6;

常量 constants

声明常量使用const关键字, 且不允许使用mut.

常量不光默认不能变,它总是不能变.

而且必须注明值的类型.

const MAX_POINTS: u32 = 100_000;
// 声明一个常量MAX_POINTS, 值是100,000.

常量在整个程序生命周期中都有效,位于它声明的作用域之中.

这使得常量可以作为多处代码使用的全局范围的值.

将用于整个程序的硬编码的值声明为常量对后来的维护者了解值的意义很用帮助。它也能将硬编码的值汇总一处,为将来可能的修改提供方便。

隐藏(Shadowing)

重复使用let关键字来隐藏.

分类
dev

Rust-Lang Notes

Rust语言学习笔记

Installation 安装

习惯的

$ brew search rust
==> Searching local taps...
rust       rustc-completion       rustup-init      uncrustify

然后顺手就可以:

$ brew install rust

这样安装完之后是可以使用rustc等的.

然而缺少rustup工具, 也因为brew同一管理路径的原因, 缺失~/.cargo目录, (不知道为啥没有至少一个软连接?).

所以出于学习阶段(在我还没弄清谁更好时), 先使用官方的方法(况且cargo是Rust的package manager):

如果brew安装过的, 别忘了先brew uninstall rust卸载掉.

$ curl https://sh.rustup.rs -sSf | sh
info: downloading installer

Welcome to Rust!

This will download and install the official compiler for the Rust programming
language, and its package manager, Cargo.

It will add the cargo, rustc, rustup and other commands to Cargo's bin
directory, located at:

  /Users/blodely/.cargo/bin

This path will then be added to your PATH environment variable by modifying the
profile files located at:

  /Users/blodely/.profile
  /Users/blodely/.zprofile

You can uninstall at any time with rustup self uninstall and these changes will
be reverted.

Current installation options:

   default host triple: x86_64-apple-darwin
     default toolchain: stable
  modify PATH variable: yes

1) Proceed with installation (default)
2) Customize installation
3) Cancel installation
1

info: syncing channel updates for 'stable-x86_64-apple-darwin'
info: latest update on 2017-08-31, rust version 1.20.0 (f3d6973f4 2017-08-27)
info: downloading component 'rustc'
 35.1 MiB /  35.1 MiB (100 %) 121.6 KiB/s ETA:   0 s
info: downloading component 'rust-std'
 49.0 MiB /  49.0 MiB (100 %) 128.0 KiB/s ETA:   0 s
info: downloading component 'cargo'
  2.6 MiB /   2.6 MiB (100 %) 124.8 KiB/s ETA:   0 s
info: downloading component 'rust-docs'
  3.6 MiB /   3.6 MiB (100 %) 115.2 KiB/s ETA:   0 s
info: installing component 'rustc'
info: installing component 'rust-std'
info: installing component 'cargo'
info: installing component 'rust-docs'
info: default toolchain set to 'stable'

  stable installed - rustc 1.20.0 (f3d6973f4 2017-08-27)


Rust is installed now. Great!

To get started you need Cargo's bin directory ($HOME/.cargo/bin) in your PATH
environment variable. Next time you log in this will be done automatically.

To configure your current shell run source $HOME/.cargo/env

这里当然猴急的运行source $HOME/.cargo/env,

再就测试一下:

$ rustc --version
rustc 1.20.0 (f3d6973f4 2017-08-27)

一切正常.

Hello, world

$ vim main.rs

然后录入:

fn main() {
    println!("Hello, world!~");
}

编译:

$ rustc main.rs

运行二进制文件:

$ ./main
Hello, world!~

Cargo

Cargo命令给出的解释是: Rust's package manager.

好吧, 使用Cargo来创建一个工程看看.

$ cargo new hello_cargo --bin
    Created binary (application) `hello_cargo` project

这样就创建了一个binary即应用程序(而不是一个库)的工程了.

cd进去发现, 还给默认初始化成一个git仓库了.

$ git status
On branch master

Initial commit

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    .gitignore
    Cargo.toml
    src/

文件结构已归好, 还增加git ignore文件.

查阅文档, --vcs参数可控制此项.

然后这个Cargo.toml文件类型让我为之一震...

toml = Tom's Obvious, Minimal Language GithubRepo

$ cat Cargo.toml
[package] # 段落标题; 配置一个包
name = "hello_cargo"
version = "0.1.0"
authors = ["Luo Yu <indie.luo@gmail.com>"]

[dependencies] # 项目依赖的crates列表(crate: Rust代码包)

构建与运行:

$ cargo build # cargo run
   Compiling hello_cargo v0.1.0 (file:///Users/blodely/Desktop/hello_cargo)
    Finished dev [unoptimized + debuginfo] target(s) in 3.27 secs
$ ./target/debug/hello_cargo
Hello, world!

Author

Luo Yu

indie.luo@gmail.com

Tuesday, September 12, 2017

分类
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

Emacs 新手笔记

Learning Emacs

还在Kotei的时候, 跟着一个Tuts+教程, 花了4天熟悉Vim.
从此入了Vim阵营, 感叹它在啥环境下都有.
那时也留下了学习emacs的念想.
这么多年过去, 是时候付诸实践啦~

会持续在此更新相关笔记.

注解

C代表Ctrl

M代表Meta键(Alt键)

Operations

终止emacs会话C-x C-c

退出正在键入的命令C-g

Screen-moving Operations

下一屏C-v, 上一屏M-v

光标所在字符的 居中/居上/居下C-l

Cursor-moving Operations

前一行C-p (Previous line)
退一格C-b (Backward)
进一格C-f (Forward)
下一行C-n (Next line)

进一词M-f (Forward)
退一词M-b (Backward)

行头C-a
行尾C-e
句头M-a
句尾M-e

篇头M-<
篇尾M->
<>键都处于上键位置, 所以输入时是需要按住Shift键.

位移命令可接受数字参数, 使用C-u录入数字, 然后会被重复作用到后续的位移命令上.
按住M输入数字也等同于此操作.
例如C-u 8 C-f会前进8个字符.

Author

Luo Yu
Friday, September 8, 2017