创建pod 私库 && 更新私库

  1. 在服务器上创建一个git工程,如HubKit

  2. 使用pod命令创建swift工程,pod将自动帮你完成xcode的很多操作

    1
    pod lib create HubKit
  3. 修改第一步生成的HubKit.podspec文件,主要包括:
    s.summary
    s.homepage
    s.source 改成第一步的git路径
    增加 s.swift_version = ‘4.0’

  4. 将整个工程上传到第一个创建的git服务器

    1
    2
    3
    4
    5
    6
    git remote add origin https://git.dev.tencent.com/chenglini/HubKit.git
    git add .
    git commit -a -m "init"
    git push --set-upstream origin master
    git tag 0.1.0
    git push --tag
  5. 检查pod库

    1
    pod lib lint

如果有以下出错提示:

1
- ERROR | [iOS] unknown: Encountered an unknown error (Could not find a `ios` simulator (valid values: com.apple.coresimulator.simruntime.ios-12-2, com.apple.coresimulator.simruntime.tvos-12-2, com.apple.coresimulator.simruntime.watchos-5-2). Ensure that Xcode -> Window -> Devices has at least one `ios` simulator listed or otherwise add one.) during validation.

解决方案:更新pod

1
sudo gem install -n /usr/local/bin cocoapods

  1. 检查spec文件

    1
    pod spec lint
  2. 创建私库pod服务器,如podSpec

    1
    pod repo add PrivServer https://git.dev.tencent.com/chenglini/podSpec.git
  3. 创建私库并上传到私库服务器

    1
    pod repo push PrivServer HubKit.podspec --sources=https://git.dev.tencent.com/chenglini/podSpec.git
  4. 使用的时候,在podfile文件中加入

    1
    2
    3
    source 'https://git.dev.tencent.com/chenglini/podSpec.git'
    ...
    pod 'HubKit'

更新私库

  1. 更新代码,更新私库版本号,然后执行
    1
    pod lib lint --use-libraries --allow-warnings

如果pod依赖私有库,则提交私库到私有仓库的时候,可以使用

1
pod lib lint --sources=PrivServer

如果依赖多个私有库,则使用:

1
pod lib lint --sources=PrivServer,REPO_NAME2,REPO_NAME3,master

  1. 将代码提交到远程代码仓库,并设置tag为私库到新版本号

    1
    2
    git tag 2.0
    git push --tags
  2. 最后把修改过的本地索引加到cocoapods 的 master 的索引中去

    1
    pod repo push  PrivServer HubKit.podspec --use-libraries --allow-warnings

ios 远程推送/本地推送

  1. Notification Service Extension中,更改推送消息的声音

    1
    bestAttemptContent.sound = UNNotificationSound.init(named: UNNotificationSoundName("ring.caf"))

    注意:

    • ring.caf 需要同时加入app 主target和消息推送的target
    • 格式为wav、caf、aiff
    • mac系统自带转换工具: afconvert Submarine.aiff sub.caf -d ima4 -f caff -v
    • avplayer在后台是没法直接使用的

AudioPlayer播放没有声音

问题代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class CallManager: NSObject {
static let shared = CallManager()
...
func ring() { //响铃
let audio = AVAudioSession.sharedInstance()
do {
try audio.setCategory(.ambient)
try audio.setActive(true)
guard let file = Bundle.main.path(forResource: "shake_sound.mp3", ofType: nil) else {
return
}
let url = URL(string: file)
let player = try? AVAudioPlayer(contentsOf: url!)
player?.volume = 1
player?.prepareToPlay()
player?.play()
} catch {
print(error)
}
}
}

解决方案:
把player的定义从函数中提出来,定义成全局变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class CallManager: NSObject {
static let shared = CallManager()
...
var player:AVAudioPlayer? = nil
func ring() { //响铃
let audio = AVAudioSession.sharedInstance()
do {
...
player = try? AVAudioPlayer(contentsOf: url!)
...
} catch {
print(error)
}
}
}

app开发的一些原则

  • 非用户操作,后台自己进行的操作,如果发生错误不应该有提示语。
  • 需要注意消息推送证书有效期,提前更新(服务器侧)
  • 版本发布前的例行检查:
    • 版本号
    • 引导页是否正确配置
  • 英文词条的首字母大小写问题

xcode人为增加编译告警

1、依次选择 TARGETS → Build Phases;
2、点击 Build Phases 内左上角的 ‘+’ 号;
3、选中 New Run Script Phase 选项;
4、输入以下代码即可:

1
2
3
TAGS="TODO:|FIXME:|WARNING:"
echo "searching ${SRCROOT} for ${TAGS}"
find "${SRCROOT}" \( -name "*.swift" \) -print0 | xargs -0 egrep --with-filename --line-number --only-matching "($TAGS).*\$" | perl -p -e "s/($TAGS)/ warning: \$1/"

静态库的兼容真机和模拟器的问题

Q: 项目上使用了第三方提供的静态库,但只有真机版本,不含模拟器版本;导致我们的项目在模拟器环境下无法编译通过

A:

  1. 自己建一个同名的工程, 假如是Goal
  2. 把第三方库的头文件都拷贝进去
  3. 把所有的接口都使用假函数实现一遍,然后编译出模拟器使用的版本
  4. 把第三方的静态库lib1.a和我们编译出来的lib2.a合并:lipo -create lib1.a lib2.a -output libGoal.a

UITableViewController

Q:UITableViewController的section header的字体是黑色的,且比较大,怎样才能改小?
A:初始化的时候,style设置成.grouped

Q:怎样在表格下方添加按钮
A: 把按钮添加到tablefooterview就行

Q: 如何在保留单元格分割线的情况下,去掉section上下两根与单元格等长的分割线
A: 有以下几种方法

  1. tablestyle从.groupd 改成 .plain
  2. 将cell separator的颜色改成表格的背景色 …
  3. 将cell separatorstyle改成.none,然后根据自己的需要手动添加

Q: 如何将cell的四个角设置成圆角
A: 设置cell.layer.mask就可以,但需要注意设置的时机,cellForRowAt 回调中,cell的size是默认值320*44
错误实例:

1
2
3
4
5
6
7
8
9
10
11
12
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) ->  UITableViewCell {
let corners:UIRectCorner = [.topLeft, .topRight, .bottomLeft, .bottomRight]
if !corners.isEmpty {
let borderLayer = CAShapeLayer()
borderLayer.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: view.frame.size.width-40, height: cell.bounds.size.height+1))
let path = UIBezierPath(roundedRect: borderLayer.frame,
byRoundingCorners: corners,
cornerRadii: CGSize(width: 8, height: 8))
borderLayer.path = path.cgPath
cell.layer.mask = borderLayer
}
}

正确:

1
2
3
4
5
6
7
8
9
10
11
12
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let corners:UIRectCorner = [.topLeft, .topRight, .bottomLeft, .bottomRight]
if !corners.isEmpty {
let borderLayer = CAShapeLayer()
borderLayer.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: view.frame.size.width-40, height: cell.bounds.size.height+1))
let path = UIBezierPath(roundedRect: borderLayer.frame,
byRoundingCorners: corners,
cornerRadii: CGSize(width: 8, height: 8))
borderLayer.path = path.cgPath
cell.layer.mask = borderLayer
}
}

如何实现半透明的uiviewcontroller

目标:通过self.present弹出新窗口,达到半透明的效果;类似uiviewcontroller

错误的位置:

1
2
3
4
5
override func viewDidLoad() {
super.viewDidLoad()
self.modalPresentationStyle = .overCurrentContext
view.backgroundColor = UIColor.lightGray.withAlphaComponent(0.5)
}

正确的位置:

1
2
3
4
5
6
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)

self.modalPresentationStyle = .overCurrentContext
view.backgroundColor = UIColor.lightGray.withAlphaComponent(0.5)
}

原因:
当新窗口弹出的动画结束后,底层的view其实已经不存在了,所以半透明就看不见他了:
After your modal view animates in, it is resized to be equal in size to its parent view. What you can do is inside your viewDidAppear:, take a picture of the parentController’s view, then insert a UIImageView containing the picture of the parent at the back of your own view’s list of subviews:

但如果在init中设置了alpha值,系统貌似帮我们做了这些事。

POSTMAN

官方文档:
https://learning.getpostman.com/docs/postman/scripts/postman_sandbox/

常用语法:
// 获取response返回内容
var rsb = responseBody; // 是字符串格式

// 获取环境变量
var v = pm.environment.get(“变量名称”);

// 设置环境变量 只能存储字符串,如果是对象的话则无法在下次运行时获取到内容
// 如需要存储JSON数据,可以用JSON.stringify(..)存储,再用JSON.parse(..)转化为对象使用
pm.environment.set(“变量名称”, 变量内容);

// 清除某个环境变量
pm.environment.unset(“环境变量名”);

// 获取全局变量和普通变量
var gb = pm.globals.get(“全局变量名”);
var nm = pm.variables.get(“普通变量名”);

// Javascript 获取变量类型
console.log( typeof pm.enviroment );

//反应时间必须少于200毫秒
tests[“Response time is less than 200ms”] = responseTime < 200;

//判断反应代号是否等于某一个指定的代号
tests[“Status code name has string”] = responseCode.name.has(“Created”);

,