作者: xiao, yanzi

苹果知道他的应用库很难找到应用吗

每次找应用都要找半天,分类也乱七八糟,支付宝不在财务里面,小米 WiFi 在财务里,shazam 不在工具里面,天气股票翻译放在阅读里面,电话信息在社交文件夹里联系人 app 就跑到效率与财务里了,能不能好好玩了。。。
还不能自定义,也没有全部应用的文件夹,我默认是用九键输入法,下拉搜也不是很方便,到*后实在烦了只能喊 siri 帮忙打开,
这个 app 资源库 感觉就是又要整应用抽屉又不想跟安卓一样,硬生生整一套出来,特色是有了就是比原来一股脑都放在桌面效率还低。。。
46 条回复    2021-04-06 10:21:16 +08:00
qq1204076437
    1

qq1204076437   17 小时 7 分钟前

感觉资源库应该允许用户自己调整。
superrichman
    2

superrichman   17 小时 6 分钟前 via iPhone

没用过这个功能,可以关掉吗?
di11wei
    3

di11wei   17 小时 4 分钟前

常用的我就放出来,或者用 Siri 建议小组件,只留一屏,其他的都在资源库里,随缘用吧。
NGUTHONG
    4

NGUTHONG   17 小时 4 分钟前 via iPhone   ❤️ 1

@qq1204076437 对啊,应该要让人可以自定义才比较合理
NGUTHONG
    5

NGUTHONG   17 小时 1 分钟前 via iPhone

@di11wei 我也是这样,但是一些学习类的 app 只要收到资源库就从此压箱底了,还有一些根本不怎么用的工具类应用堆积在那边?
agdhole
    6

agdhole   16 小时 52 分钟前 via iPhone

我都是搜索的,从来不去慢慢找
CastleBUPT
    7

CastleBUPT   16 小时 46 分钟前 via iPhone

如果想自定义,不是建文件夹放桌面就行了吗,这个分类是 app 厂自己定义的
0x6c696e71696e67
    8

0x6c696e71696e67   16 小时 39 分钟前

*蠢的是在资源库不小心下拉出搜索框要在右上角关掉
NGUTHONG
    9

NGUTHONG   16 小时 37 分钟前 via iPhone

@CastleBUPT 主要还是应用太多,有些使用频率低一点的就不会放到桌面上占位置
CastleBUPT
    10

CastleBUPT   16 小时 32 分钟前 via iPhone

@0x6c696e71696e67
你左滑右滑试一下?
@NGUTHONG
是的啊,这个功能就是照顾懒人,如果还能调整,又调乱了怎么办。一般来说 app 厂对自己的产品定位更准确,比如王者荣耀肯定在游戏里没跑的吧。至于有些 app 莫名其妙跑到了财务,建议跟 app 客服反馈一下

Persipa
    11

Persipa   16 小时 30 分钟前

@0x6c696e71696e67 屏幕底部往上滑可以关掉~

我用资源库的情况只有 我需要用的 app 如果能一眼看到 就点,否则的话直接搜索或叫 Siri

NGUTHONG
    12

NGUTHONG   16 小时 30 分钟前 via iPhone

@0x6c696e71696e67 上滑就可以推出了啊
NGUTHONG
    13

NGUTHONG   16 小时 24 分钟前 via iPhone

@CastleBUPT 主要这个功能就是设计让人收纳使用频率比较低的 app,结果收纳进去就变得很难找到就很让人烦躁,就真的还不如以前我自己归类文件夹省心
NGUTHONG
    14

NGUTHONG   16 小时 18 分钟前 via iPhone

@Persipa 真的都习惯叫 siri 帮忙了,每次猜应用在哪个文件夹真的还蛮费脑的
hkezh
    15

hkezh   15 小时 53 分钟前 via iPhone

应该给这个功能开关。这玩意对我来说就是浪费一个页面
Zien
    16

Zien   15 小时 37 分钟前 via iPhone

主要是很多不好分类,加上国内厂商乱分类,只要跌不强制他们,他们*对不会规范。
grimpil
    17

grimpil   15 小时 36 分钟前 via Android

找支付宝得去社交分类里面吧?
thx2u
    18

thx2u   14 小时 30 分钟前

就是一 touch bar,食之无味,弃之不可惜。
苹果在越来越优雅的漩涡里越来越难用。
aneureka
    19

aneureka   13 小时 39 分钟前 via iPhone

@0x6c696e71696e67 #8 左滑就行
NGUTHONG
    20

NGUTHONG   12 小时 58 分钟前 via iPhone

@hkezh 然而苹果向来都不会给人选择的空间
NGUTHONG
    21

NGUTHONG   11 小时 52 分钟前 via iPhone

@Zien 然而连苹果自家的 app 都没有好好分类清楚,其他厂肯定也抓瞎,我觉得她本身分的这几个类别就有问题
Zien
    22

Zien   11 小时 47 分钟前 via iPhone

@NGUTHONG 是的,不过其实自己手动分有时候也挺茫然的,我觉得大体上还蛮好用的,实在不好找的搜一下就好。
yitingbai
    23

yitingbai   11 小时 23 分钟前

苹果这些年不知道在干啥, 取消了 3D-Touch 的功能, 大大降低了我购买下一部 iphone 的欲望, 到现在还在用 xs max, 这么好用的功能都被阉割了, 我都想换回安卓了
NGUTHONG
    24

NGUTHONG   10 小时 14 分钟前 via iPhone

@Zien 自己归类的起码能有点印象要用的时候还能找到?
NGUTHONG
    25

NGUTHONG   10 小时 12 分钟前 via iPhone

@yitingbai 3DTouch 这硬件成本这么高的东西,取消了利润不就上去了吗
theolin
    26

theolin   10 小时 5 分钟前   ❤️ 1

我一开始也是这么吐槽的。但是 app 资源库用上一段时间之后,会发现越来越好用。因为它的分类也好,每个分类里面的 app 也好,都会根据你的使用来动态进行调整。每个分类可以显示 7 个*常用的 app,其中前 3 个可以直接点击。完全够用了。真正需要找的 app,只有那些偶尔运行一次的。
theolin
    27

theolin   10 小时 4 分钟前

@0x6c696e71696e67 不是啊。从底部往上滑或者从右边往左滑一下都可以退出搜索啊。
NGUTHONG
    28

NGUTHONG   1 小时 42 分钟前

@theolin 可能是我软件装太多,大部分还不是天天用的 app,就常常要去找
Leonard
    29

Leonard   1 小时 18 分钟前

我都是用 spotlight 搜索
EnsPEn
    30

EnsPEn   1 小时 11 分钟前 via iPhone

你不说我还真忘了*后一屏的这个玩意了,我还是按照以前的逻辑,全部在页面上自己分类
ALVC666
    31

ALVC666   1 小时 10 分钟前

app 越来越多 我已经忍受不了滑动几屏去找 app 的操作了
现在都是直接搜索
xidaduo
    32

xidaduo   1 小时 8 分钟前

这个主要是厂商自己提交 App 审核的时候定义的 App 类型,苹果分类也是依据这个来分的
flashrick
    33

flashrick   1 小时 4 分钟前

@yitingbai 可以一直没有 3dtouch,但是让我体验过了好处后面取消了,我就不想买了。 可以一直都是人脸识别开锁,但是本来方便的指纹换成人脸,我完全不想买了。
UnPace
    34

UnPace   1 小时 2 分钟前

苹果的应用库有个搜索功能,类似于通讯录按照应用名称拼音首字母排序导航的,我感觉这个资源库还不如直接按照这种方式展示,很方便快捷。
Pogbag
    35

Pogbag   1 小时 2 分钟前

我以为只有我觉得难用
dcty
    36

dcty   58 分钟前

常年用搜索的人表示习惯了
qq1204076437
    37

qq1204076437   40 分钟前

@CastleBUPT 资源库会自动帮助做分类,只需要做调整,会减少很多麻烦。而且资源库视图信息密度高很多,更适合丢一堆使用频率低的应用。
horsley
    38

horsley   36 分钟前

常年搜索+1,这个分类是上架的时候应用提供方自己填的
PostMeridiem18
    39

PostMeridiem18   28 分钟前

1. 应用库可以关
2. Spotlight 搜索才是找到应用的*速方式
3. 用九宫格为什么会导致下拉搜索不方便?
glaucus
    40

glaucus   13 分钟前   ❤️ 2

Spotlight 搜索应用很难用啊。。。
比如今日头条,搜今日可以,搜今日头条可以,搜头条就找不到。。。
NGUTHONG
    41

NGUTHONG   11 分钟前

@Leonard
@dcty *后还是搜索比较快。。
@PostMeridiem18 应用库哪里可以关?没看到有开关,九宫格慢是因为九宫格主要靠输入法联想,一些比较不常见的 app 名称他联想不到就得打开选字,如果找英文 app 就还要切输入法,没有用全键的那么方便,全键的不管英文中文 app 都只要输入前几个字母就可以筛选出来,快很多
alfchin
    42

alfchin   9 分钟前 via iPhone

@glaucus 这个锅应该是头条的
搜手机淘宝输入淘宝是能搜到的
wellsc
    43

wellsc   6 分钟前

搜英文名可解
PostMeridiem18
    44

PostMeridiem18   3 分钟前

@NGUTHONG 抱歉…我记错了,应用库关不掉,只有里面的通知小红点可以单独开关。如果实在不习惯的话就手动把所有的 App 拖到主屏幕上好了,然后让系统自动添加新应用…然后再找个地方塞个 Siri 应用建议(
glaucus
    45

glaucus   3 分钟前

@alfchin #42 大部分是正常的,但是感觉头条也不至于主动去配置得让自己没法被搜到吧,不懂为啥用户能看到得应用名也能出现这种问题
PeterZzz
    46

PeterZzz   2 分钟前 via iPhone

苹果他知道,但是他不改

MBP 安装 mac 系统监测工具 iStats 遇到的问题,并逐一解决

今天搞视频,MBP 呼呼响,突然想装个软件查看一下 CPU 温度,风扇转速什么的。 *简单是用 Ruby 的 iStats,直接指令安装,简单又小巧。

常规操作:

sudo gem install iStats

谁知道我电脑升级到 10.14 以后就很久没搞过 gem 了,估计生锈,报错:

ERROR: Failed to build gem native extension.

再往下看

You might have to install separate package for the ruby development
environment, ruby-dev or ruby-devel for example.

噢,ruby 都没装啊?可能被我清理掉了。。。 直接装 xcode-select

xcode-select --install

Easy 安装成功,毕竟是 xcode,果子自家软件。

再来安装一次 iStats

sudo gem install iStats

又报错,You don’t have write permissions for the /usr/bin directory. 好像是 10.14 提高了安全等级,不允许安装到 /usr/bin 那就指定到其他地方:

sudo gem install iStats -n /usr/local/bin 

安装成功!~ 执行指令 iStats 运行:

cZUX28.png

2 条回复    2021-04-02 12:37:03 +08:00
suntorrent
    1

suntorrent   12 小时 17 分钟前

10.15 Catalina: make failed
make: *** No rule to make target `/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/include/ruby-2.6.0/universal-darwin19/ruby/config.h’, needed by `smc.o’. Stop.
easonl
    2

easonl   5 小时 12 分钟前

@suntorrent 我是 Big Sur,没遇到你这种报错~ 你试试升级以下你的 ruby 和 gem

吐槽 AirPods?

AirPods 2,佩戴舒服无感,左右交替带一天。
开始吐?
开启入耳检测:经常出现被认为拿出耳机,暂停播放,只能手动重新放耳朵里,而且还得来回扭动待耳机检测成功!
关闭入耳检测:不会再有断播,不过耳机双击切换大概率失效!放充电盒后手机外放会出现已连接耳机的状况(音频直接被耳机接管)

什么,用 Hey Siri 切歌?这家伙懒得要死,基本不理我!

31 条回复    2021-04-02 16:43:58 +08:00
silencelixing
    1

silencelixing   8 小时 7 分钟前

我*受不了的是,耳机有电放进充电盒,拿出来没电了
Shook
    2

Shook   7 小时 52 分钟前

我只用来听歌。
zoeleeeeee
    3

zoeleeeeee   7 小时 46 分钟前

完全没遇到过,使用一切正常,也没有误认为是拿出耳机之类的。建议你找苹果客服看看是不是你那个耳机有问题。
ChangQin
    4

ChangQin   7 小时 45 分钟前

@silencelixing 没错!这种情况一般是耳机有电,盒子没电了
Nishino
    5

Nishino   7 小时 45 分钟前

没遇到过,你这估计坏了吧
zoeleeeeee
    6

zoeleeeeee   7 小时 44 分钟前

我也经常用 airpods 唤出 siri,使用两三年了,从没出过问题,pro 也没问题。siri 必须联网才会响应,如果你联网了还是不行,检查一下 siri 设置,不行的话还是建议联系客服
wipbssldo
    7

wipbssldo   7 小时 42 分钟前

「左右交替带一天。」是什么操作
haorrs
    8

haorrs   7 小时 40 分钟前

坚持只带一只耳朵?
dier
    9

dier   7 小时 18 分钟前

我也觉得你应该咨询一下苹果客服,看是不是耳机有问题
dier
    10

dier   7 小时 17 分钟前

@silencelixing
@ChangQin
耳机还有反向给盒子充电的骚操作??

w99wjacky
    11

w99wjacky   7 小时 16 分钟前

入耳检测的问题没遇到过,你这估计坏了
Hey Siri 肯定有用的,先检查下是否开了 Siri
w99wjacky
    12

w99wjacky   7 小时 16 分钟前

推荐先保修
ericwoflskin
    13

ericwoflskin   7 小时 6 分钟前

个体问题,下一个!
NilChan
    14

NilChan   7 小时 3 分钟前 via Android

入耳检测这么坑的吗?
StyxS
    15

StyxS   7 小时 2 分钟前

对于我来说*坑的是连着电脑,手机拿出来看下就被抢走了
电脑蓝牙还连着,但是没声音
cszchen
    16

cszchen   6 小时 50 分钟前

建议看一下佩戴的姿势,耳机屁股朝下,或者朝前角度不要太大,对着下巴就行了
DEVN
    17

DEVN   6 小时 48 分钟前

3 代 完美躲避这些问题 ?
bg7dcw
    18

bg7dcw   6 小时 40 分钟前

hi siri: hey, say (去声) rui(三声)
wezzard
    19

wezzard   6 小时 36 分钟前

重置一下试试?
Leonard
    20

Leonard   6 小时 25 分钟前

@dier #10 不是反向充电,只是盒子没给耳机充电,耳机自己耗电耗光了
ftu
    21

ftu   6 小时 10 分钟前

的确,有利有弊,躺着很容易暂停,遂关闭入耳检测

AirPods 充电盒没电了也不会提醒,这个有待改良,还有 Siri 带着口罩路上走,基本正常音量叫不 Siri 出来

freakJacker
    22

freakJacker   5 小时 31 分钟前

保修的,拿去检测一下。坏了会给你换一个新的
iloveayu
    23

iloveayu   5 小时 17 分钟前

双击的位置比较重要:
%title插图%num
FartNoSound
    24

FartNoSound   5 小时 15 分钟前

对我来说*恶心的还是 iPhone 和 Mac 不能同时开蓝牙,同时连接,一会连这个,一会连那个的。
xujia1998
    25

xujia1998   3 小时 1 分钟前

airpods pro 能打电话吗?我都怀疑我买到残品了,每次打电话对面说我声音小
zc847666533
    26

zc847666533   2 小时 45 分钟前

@xujia1998 确实声音很小,我每次用这个打电话也是,好几次对面都问我离电话很远么
misaka19000
    27

misaka19000   2 小时 36 分钟前

没遇到过。。。我还是并夕夕买的。。。
nobodyknows
    28

nobodyknows   2 小时 19 分钟前

@silencelixing 试过几次,好像放到某些不兼容的无线充电器会放电 – -!
wipbssldo
    29

wipbssldo   1 小时 36 分钟前

@silencelixing 充电盒没电,没办法告诉耳机进入睡眠,耳机一直处于工作状态,耳机很快就没电
AndyZhuAZ
    30

AndyZhuAZ   1 小时 34 分钟前

*近我的 pro 的 Siri 也不好使了,叫起来很难。。。不知道是不是堵了
mantout
    31

mantout   1 小时 7 分钟前

@ChangQin #4 这种情况我遇到过一两次,我猜测的原因是充电仓底部有灰尘之类的东西,导致耳机接触不良,一直处于工作状态,把电放光了。

问一下大家的 iPad Pro 2020 12.9 照片滑动卡么?

具体表现是:

1 、照片缩略图页面上下滑动经常特别卡,严重的时候感觉带有抖动

2 、有的照片点去要一秒左右才从模糊变清楚

3 、每张照片左滑右滑上一张下一张也经常卡

7 条回复    2021-04-02 17:09:04 +08:00
BlackCode
    1

BlackCode   3 小时 43 分钟前 via iPhone

“一秒左右才从模糊变清楚”

是不是开了照片的“优化 iPhone 存储空间”

zach
    2

zach   3 小时 33 分钟前

@BlackCode iCloud 照片是关闭的,现在怀疑是 iOS14.4.2 的原因,刚才试了下 app store 上下滑动也是卡卡的,整个系统都不流畅,照片尤其严重
tedeastside
    3

tedeastside   1 小时 53 分钟前 via iPhone

开了 60hz 吗
paopaosa
    4

paopaosa   1 小时 44 分钟前

重启过吗?
terrychanin
    5

terrychanin   1 小时 39 分钟前

实测没有这种情况,建议重启试试
littlewing
    6

littlewing   1 小时 29 分钟前 via iPhone

先说一下你有几百 G 的照片吧
Ciicing
    7

Ciicing   41 分钟前

@zach 商店我的 2020 11 款也会偶尔卡一下

Mac 上有哪些好用的 PDF 阅读软件啊?

非常讨厌 WPS,除了 WPS 外其他都可以推荐…
20 条回复    2021-04-02 17:43:58 +08:00
CenN
    1

CenN   2 小时 37 分钟前

我觉得预览挺好用的
TimePPT
    2

TimePPT   2 小时 36 分钟前

PDF Expert
66beta
    3

66beta   2 小时 35 分钟前

预览
chrome
EasonC
    4

EasonC   2 小时 34 分钟前 via iPhone

marginnote3
bear2000
    5

bear2000   2 小时 28 分钟前

自带的预览*好用
IgniteWhite
    6

IgniteWhite   1 小时 53 分钟前 via iPhone

楼上推荐的都不错。补充:Skim,这款方便配合 Vim 写 LaTeX 用,能实时更新,反向搜索
Zien
    7

Zien   1 小时 32 分钟前 via iPhone

系统自带的,或者 chrome 的 kami 插件(批注)和划词翻译带的插件( pdf 划词翻译)
littlewing
    8

littlewing   1 小时 24 分钟前 via iPhone

预览.app
sungnix
    9

sungnix   59 分钟前

PDF Guru 挺不错,不编辑的话用免费版足够了。
w2ex2019
    10

w2ex2019   57 分钟前

PDF Expert +1

AllenHua
    11

AllenHua   55 分钟前

Preview.app
ftu
    12

ftu   53 分钟前

一般用 PDF Expert
shoujiaxin
    13

shoujiaxin   44 分钟前 via iPhone

Preview,PDF Expert 太吃内存了
sunkpfly
    14

sunkpfly   38 分钟前

PDF Expert +2
clyecao
    15

clyecao   27 分钟前

chrome(+ kami) + 1
ExplorerLog
    16

ExplorerLog   17 分钟前

firefox
Johnoo
    17

Johnoo   15 分钟前

PDF Expert +10086 ,关键是还能修改矢量 PDF
gxy2825
    18

gxy2825   14 分钟前

PDF Reader Pro
Roykira
    19

Roykira   13 分钟前

*近发现 marginnote3 还不错。
with
    20

with   1 分钟前

PDF Guru +1

iOS开发-NSThread子线程autoreleasepool的问题

前言
对于 NSThread 开启的子线程,我们需要在 main 函数中创建一个autoreleasepool,当我们从其他线程跳转到该线程执行时,对象是如何释放的呢?主线程是由于runloop的循环,在beforeWait时,触发主线程的autoreleasepool的pop和push操作来释放的,而子线程并没有自动添加这些observer,那么如何释放的?

探索
跳转到我们线程执行任务的方法如下,使用了performSelector:系列的方法。

1 OBJC_EXTERN void _objc_autoreleasePoolPrint(void);
2 @implementation GrowingDispatchManager
3
4 + (void)dispatchInGrowingThread:(void (^_Nullable)(void))block {
5     if ([[NSThread currentThread] isEqual:[GrowingThread sharedThread]]) {
6         block();
7     } else {
8         [GrowingDispatchManager performSelector:@selector(dispatchBlock:)
9                                        onThread:[GrowingThread sharedThread]
10                                      withObject:block
11                                   waitUntilDone:NO];
12     }
13 }
14
15 + (void)dispatchBlock:(void (^_Nullable)(void))block {
16
17     NSLog(@”runloop %@”,[NSRunLoop currentRunLoop]);
18 //    _objc_autoreleasePoolPrint();
19     if (block) {
20         block();
21     }
22 //    _objc_autoreleasePoolPrint();
23 }

打印当前runloop,确定是没有像主线程那样添加observer,如下:

1 2021-02-03 23:14:42.112259+0800 Example[5075:57255] runloop <CFRunLoop 0x600000dbdb00 [0x7fff80617cb0]>{wakeup port = 0x9203, stopped = false, ignoreWakeUps = false,
2 current mode = kCFRunLoopDefaultMode,
3 common modes = <CFBasicHash 0x600003fe25b0 [0x7fff80617cb0]>{type = mutable set, count = 1,
4 entries =>
5
6 }
7 ,
8 common mode items = <CFBasicHash 0x600003fe2bb0 [0x7fff80617cb0]>{type = mutable set, count = 1,
9 entries =>
10
11 }
12 ,
13 modes = <CFBasicHash 0x600003fe27f0 [0x7fff80617cb0]>{type = mutable set, count = 1,
14 entries =>
15
16
17 FBasicHash 0x600003fe25e0 [0x7fff80617cb0]>{type = mutable set, count = 2,
18 entries =>
19
20
21 }
22 ,
23
24 entries =>
25 }
26 ,
27
28
29
30 },
31
32 }
33 }

那么如何释放的呢,通过_objc_autoreleasePoolPrint()打印自动释放池堆栈,确定对象没有堆积,是进行释放过了。

常驻线程实现代码如下:

2 // GrowingThread.m
3 // GrowingAnalytics
4
5 #import “GrowingThread.h”
6
7 @interface GrowingThread () {
8     dispatch_group_t _waitGroup;
9 }
10
11 @property (nonatomic, strong, readwrite) NSRunLoop *runLoop;
12
13 @end
14
15 @implementation GrowingThread
16
17 + (instancetype)sharedThread {
18     static GrowingThread *thread;
19     static dispatch_once_t onceToken;
20     dispatch_once(&onceToken, ^{
21         thread = [[GrowingThread alloc] init];
22         thread.name = @”com.growing.thread”;
23         [thread start];
24     });
25     return thread;
26 }
27
28 – (instancetype)init {
29     self = [super init];
30     if (self) {
31         _waitGroup = dispatch_group_create();
32         dispatch_group_enter(_waitGroup);
33     }
34     return self;
35 }
36
37 – (void)main {
38     @autoreleasepool {
39         _runLoop = [NSRunLoop currentRunLoop];
40         dispatch_group_leave(_waitGroup);
41
42         // Add an empty run loop source to prevent runloop from spinning.
43         CFRunLoopSourceContext sourceCtx = {.version = 0,
44                                             .info = NULL,
45                                             .retain = NULL,
46                                             .release = NULL,
47                                             .copyDescription = NULL,
48                                             .equal = NULL,
49                                             .hash = NULL,
50                                             .schedule = NULL,
51                                             .cancel = NULL,
52                                             .perform = NULL};
53         CFRunLoopSourceRef source = CFRunLoopSourceCreate(NULL, 0, &sourceCtx);
54         CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
55         CFRelease(source);
56
57         while ([_runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]) {
58         }
59         assert(NO);
60     }
61 }
62
63 – (NSRunLoop *)runLoop;
64 {
65     dispatch_group_wait(_waitGroup, DISPATCH_TIME_FOREVER);
66     return _runLoop;
67 }
68
69 @end

通过断点调试,发现堆栈中确实有调用对应的NSPushAutoreleasePool和NSPopAutoreleasePool

%title插图%num
打印执行时的堆栈:

1 (lldb) bt
2 * thread #9, name = ‘com.growing.thread’, stop reason = breakpoint 2.1
3     frame #0: 0x0000000108cf5c07 GrowingAnalytics`+[GrowingDispatchManager dispatchBlock:](self=GrowingDispatchManager, _cmd=”dispatchBlock:”, block=0x0000000108cfb330) at GrowingDispatchManager.m:46:1
4     frame #1: 0x00007fff25781c30 Foundation`__NSThreadPerformPerform + 259
5     frame #2: 0x00007fff23bd4471 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
6     frame #3: 0x00007fff23bd439c CoreFoundation`__CFRunLoopDoSource0 + 76
7     frame #4: 0x00007fff23bd3b74 CoreFoundation`__CFRunLoopDoSources0 + 180
8     frame #5: 0x00007fff23bce87f CoreFoundation`__CFRunLoopRun + 1263
9     frame #6: 0x00007fff23bce066 CoreFoundation`CFRunLoopRunSpecific + 438
10   * frame #7: 0x00007fff2576b86f Foundation`-[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 211
11     frame #8: 0x0000000108d41012 GrowingAnalytics`-[GrowingThread main](self=0x0000600001285900, _cmd=”main”) at GrowingThread.m:72:16
12     frame #9: 0x00007fff257817a7 Foundation`__NSThread__start__ + 1047
13     frame #10: 0x00007fff52466e65 libsystem_pthread.dylib`_pthread_start + 148
14     frame #11: 0x00007fff5246283b libsystem_pthread.dylib`thread_start + 15

至此,对象为何释放的原因找到了,如果不是runMode:beforeDate:方法自动加上了自动释放池,就内存泄漏了,所以需要在执行的方法dispatchBlock中保险起见,都加上@autoreleasepool才是上策,这里也是忽略了这点,险些bug背锅。。。

iOS开发-逆向注入SDK之iOS越狱

越狱
这里采用使用 iphone 5S, iOS 12.4.9 为例,进行 非完美越狱

非完美越狱:重启手机越狱失效,需要再进行越狱,越狱也不麻烦,点几下就行了,不过不关机就行了哈

i4助手
安装 i4助手(爱思助手) https://www.i4.cn/ 是个很好的软件,如果你的手机变砖了,正好可以使用它刷机。不过被密码锁定的手机不行。

如果你的iphone已经开机就黑,选择合适的固件版本,进行刷机

%title插图%num

这里对其功能不做进一步说明,低版本可以直接完美越狱,我们这里仅使用它来方便访问越狱文件以及安装app。

使用unc0ver越狱并配置
unc0ver 可以方便的快速越狱你的手机,不过是非完美越狱,由于安装的时候,手机还没有越狱,官网的使用方法中,使用 iOS App Signer 的方式可行。

%title插图%num

这里以iOS开发者的角度阐述为以下几步:

安装好你的xcode,配置好环境,登录你的开发者账号。
创建一个Project,选择类型为App,这里叫它 unc0ver。
配置好你的证书,如下

%title插图%num

从钥匙串中导出你对应的p12证书,并且拖出Profile文件。(这里Profile文件部分同学可能不知道拖,见下图)
a. 鼠标移至感叹号,点击

%title插图%num

b. 长按图标,拖置桌面

%title插图%num

从 unc0ver 官网下载 unc0ver_Release_x.x.x.ipa
打开 iOS App Signer,配置ipa,p12以及选择自定义的Profile

%title插图%num

生成新的ipa,通过i4助手进行安装。

%title插图%num

如果需要信任,则设置->通用->描述文件与设备管理中信任即可。
打开 unc0ver,点击 Jailbreak 进行越狱,期间弹出 REBEL 不要管它,叉掉,继续。提示你重启就重启,该允许的允许,然后继续打开 unc0ver 继续,直到 unc0ver 完成越狱。
这个方法需要 开发证书 配置文件 重签名。网上部分安装方法,直接安装的话,会提示 entitlements 不匹配,无法进行下一步了。

越狱好后,会多出Cydia和Substitude,同时 unc0ver 显示 Re-Jailbreak

%title插图%num

安装好unc0ver之后,就需要配置 Cydia 了

配置你的Cydia
点击 Cydia->软件源->编辑->添加 添加源 build.frida.re ,apt.cydiami.com,并进行更新。
搜索 SSH ,选择 OpenSSH 进行安装
搜索 frida ,由于是 5S,我们选择 Frida for pre-A12 devices
搜索 AFC ,安装 AFC2 iOS12系统文件访问
至此,越狱完成,可以访问系统文件了。

%title插图%num

iOS开发-NSNotification源码原理学习

文章目录
问题
1. 实现原理
对于addObserver方法,为什么需要object参数?
都传入null对象会怎么样
addObserver源码逻辑
2.通知的发送时同步的,还是异步的
3. NSNotificationCenter接受消息和发送消息是在一个线程里吗?如何异步发送消息
4.NSNotificationQueue和runloop的关系
5.如何保证通知接收的线程在主线程
6.多次添加同一个通知会是什么结果?多次移除通知呢?
7.下面的方式能接收到通知吗?为什么
问题
苹果并没有开源相关代码,但是可以读下 GNUStep 的源码

或者这里下载
链接:https://pan.baidu.com/s/1F25GgeLxqKjeo10Zgfr2OQ
密码:qpka

从下列问题触发,探索下NSNotification的实现原理

实现原理(结构设计、通知如何存储的、name&observer&SEL之间的关系等)
通知的发送时同步的,还是异步的
NSNotificationCenter接受消息和发送消息是在一个线程里吗?如何异步发送消息
NSNotificationQueue是异步还是同步发送?在哪个线程响应
NSNotificationQueue和runloop的关系
如何保证通知接收的线程在主线程
页面销毁时不移除通知会崩溃吗
多次添加同一个通知会是什么结果?多次移除通知呢
下面的方式能接收到通知吗?为什么

1 // 发送通知
2 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:@”TestNotification” object:@1];
3 // 接收通知
4 [NSNotificationCenter.defaultCenter postNotificationName:@”TestNotification” object:nil];

1. 实现原理
对于addObserver:selector:name:object:会创建一个observation

1 typedef
2   id
3   SEL
4   struct Obs
5   int
6   struct NCTbl
7 } Observation;

对于Observation持有observer

在iOS SDK 8之前:不是一个类似OC中的weak类型,持有的相当与一个__unsafe_unretain指针对象,当对象释放时,会访问已经释放的对象,造成BAD_ACCESS。
在iOS SDK 8之后:持有的是weak类型指针,对nil对象performSelector不再会崩溃
name和Observation是映射关系,observer和sel包含在Observation结构体中。

此外,NSNotification维护了GSIMapTable表的结构,用于存储Observation,分别是nameless,name,cache,nameless存储没有传入名字的通知,named存储传入了名字的通知,cache用于快速缓存.

1 #define CHUNKSIZE 128
2 #define CACHESIZE 16
3 typedef struct NCTbl {
4   Observation *wildcard; /* Get ALL messages. */
5   GSIMapTable nameless; /* Get messages for any name. */
6   GSIMapTable named; /* Getting named messages only. */
7   unsigned lockCount; /* Count recursive operations. */
8   NSRecursiveLock *_lock; /* Lock out other threads. */
9   Observation *freeList;
10   Observation **chunks;
11   unsigned numChunks;
12   GSIMapTable cache[CACHESIZE];
13   unsigned short chunkIndex;
14   unsigned short cacheIndex;
15 } NCTable;

这里值得注意nameless和named的结构,虽然同为hash表

1
2 在nameless表中:
3 GSIMapTable的结构如下
4 object : Observation
5 object : Observation
6 object : Observation
7
8 —————————-
9 在named表中:
10 GSIMapTable结构如下:
11 name : maptable
12 name : maptable
13 name : maptable
14
15 maptable的结构如下
16 object : Observation
17 object : Observation
18 object : Observation

关于GSIMap结构

对于addObserver方法,为什么需要object参数?
– (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSNotificationName)aName object:(nullable id)anObject;

就是addObserver其实不用传入name也可以,传入object,当postNotification方法同样发出这个object时,就会触发通知方法。

例如这样的写法:

1 – (void)viewDidLoad {
2     [super viewDidLoad];
3     // Do any additional setup after loading the view.
4     NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
5     MyObject *obj = [MyObject new];
6     [center addObserver:self selector:@selector(doAction:) name:nil object:obj];
7     dispatch_async(dispatch_get_global_queue(0, 0), ^{
8         [center postNotificationName:@”TEST” object:obj];
9     });
10 }
11
12 – (void)doAction:(NSNotification*)sender {
13     NSLog(@”%s %@ %@”,__FUNCTION__,sender,[NSThread currentThread]);
14 }

参考 https://www.jianshu.com/p/83770200d476

都传入null对象会怎么样
你可能也注意到了,addObserver方法name和object都可以为空,这表示将会把observer赋值为 wildcard,他将会监听所有的通知。

addObserver源码逻辑
addObserver的逻辑如下

1. 根据传入的selector和observer创建Observation,并存入maptable中,如果已存在,则是从cache中取。
2. 如果name存在,则向named的maptable表中插入元素,key为name,value为GSIMapTable,GSIMapTable中存key为object,value为Observation,转入5。如果不存在则进入3
3. 如果object存在,则向nameless的maptable表中插入元素,key为object,value为Observation。如果不存在,则进入4,否则转入5
4. name和object都为空,则Observation->next=wildcard,将老的wildcard赋值为next指针,然Observation对象置为wildcard,wildcard = Observation
5.结束

2.通知的发送时同步的,还是异步的
postNotificationName的底层实现是

– (void) _postAndRelease: (NSNotification*)notification
由于内部会读取TABLE

lockNCTable(TABLE);
… //找到对应的observer对象
unlockNCTable(TABLE);

…//执行performSelector方法

1 lockNCTable(TABLE);
2 … //找到对应的observer对象
3 unlockNCTable(TABLE);
4
5 …//执行performSelector方法
6
7 lockNCTable(TABLE);
8 GSIArrayEmpty(a); //释放临时创建的数组对象 – 用于存储observer的
9 unlockNCTable(TABLE);

同步异步这个问题,由于TABLE资源的问题,同一个线程会按顺序执行,自然是同步的。

3. NSNotificationCenter接受消息和发送消息是在一个线程里吗?如何异步发送消息
由于是使用的performSelector方法,没有进行转线程,默认是postNotification方法的线程。

1
2 [o->observer performSelector: o->selector
3                                 withObject: notification];
4

对于异步发送消息,可以使用NSNotificationQueue,queue顾明意思,我们是需要将NSNotification放入queue中执行的。

有三种状态

1 typedef NS_ENUM(NSUInteger, NSPostingStyle) {
2     NSPostWhenIdle = 1,      // 当runloop处于空闲状态时post
3     NSPostASAP = 2,    // 当当前runloop完成之后立即post
4     NSPostNow = 3    // 立即post
5 };

 

1 NSNotification *noti = [NSNotification notificationWithName:@”111″ object:nil];
2 [[NSNotificationQueue defaultQueue] enqueueNotification:noti postingStyle:NSPostASAP];

参考文章 https://www.jianshu.com/p/356f7af4f2ee

4.NSNotificationQueue和runloop的关系
NSNotificationQueue的执行是依赖于runloop的,它的三种模式各自的执行时机不一样。

1 typedef NS_ENUM(NSUInteger, NSPostingStyle) {
2     NSPostWhenIdle = 1,      // 当runloop处于空闲状态时post
3     NSPostASAP = 2,    // 当当前runloop完成之后立即post
4     NSPostNow = 3    // 立即post
5 };

例如

1 void asyncQueueNotiInRunloop() {
2     dispatch_async(dispatch_get_global_queue(0, 0), ^{
3         NSLog(@”1″);
4         NSLog(@”%@”, [NSThread currentThread]);
5
6         //NSPostWhenIdle
7         //NSPostASAP
8         //NSPostNow
9         NSNotification *notification = [NSNotification notificationWithName:@”TEST” object:nil];
10         [[NSNotificationQueue defaultQueue] enqueueNotification:notification postingStyle:NSPostWhenIdle coalesceMask:NSNotificationNoCoalescing forModes:@[NSDefaultRunLoopMode]];
11         // run runloop
12         [[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSRunLoopCommonModes];
13         CFRunLoopRun();
14         NSLog(@”3″);
15     });
16 }

如果去掉run runloop部分的代码,则无法触发通知

5.如何保证通知接收的线程在主线程
由于通知的发出使用performSeletor实现,如果需要保证接收的线程在主线程,可以:

保证主线程发出
接收到通知后跳转到主线程,苹果建议使用NSMachPort进行消息转发到主线程。
https://blog.csdn.net/shengpeng3344/article/details/90206265

使用block接口addObserverForName:object:queue:usingBlock:

1 – (id <NSObject>)addObserverForName:(nullable NSNotificationName)name object:(nullable id)obj queue:(nullable NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));
2     // The return value is retained by the system, and should be held onto by the caller in
3     // order to remove the observer with removeObserver: later, to stop observation.

页面销毁时不移除通知会崩溃吗?
对于Observation持有observer

在iOS SDK 8之前:不是一个类似OC中的weak类型,持有的相当与一个__unsafe_unretain指针对象,当对象释放时,会访问已经释放的对象,造成BAD_ACCESS。
在iOS SDK 8之后:持有的是weak类型指针,对nil对象performSelector不再会崩溃
所以说不一定会崩溃,但是根据代码严谨是需要remove的

6.多次添加同一个通知会是什么结果?多次移除通知呢?
由于源码中并不会进行重复过滤,所以添加同一个通知,等于就是添加了2次,回调也会触发两次。

为什么会触发两次呢,因为- (void) postNotificationName: (NSString*)name object: (id)object的逻辑是这样的:

1. 查找所有是wildcard类型的Observation,加入数组array,即既不监听name也不监听object
2. 查找指定object但未指定name的Observation,加入数组array
3. 查找指定了相同name和object的Observation,加入数组array,当name一致但object不一致时,也不会加入到数组array,但如果传入的object!=nil,则会将name对应的maptable中,所有key为nil的Observation也加入数组。
4. 遍历array,执行performSelector
5. 清空array

第三步的意思是:如果发出一个通知,方法中传入了对象object,那么那些只监听通知name,object设置为nil的当然也可以收到,object匹配了的也可以收到,object不匹配的则收不到。

关于多次移除,并没有问题,因为会去map中查找,找到才会删除。当name和object都为nil时,会移除所有关于该observer的WILDCARD

7.下面的方式能接收到通知吗?为什么

1
2 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:@”TestNotification” object:@1];
3
4 [NSNotificationCenter.defaultCenter postNotificationName:@”TestNotification” object:nil];

根据postNotification的实现,会找到key为TestNotification的maptable,再从中选择key为nil的observation,所以是找不到以@1为key的observation的

iOS开发-ViewController的生命周期相关

文章目录
ViewController生命周期
加载流程
didReceiveMemoryWarning
View的layoutSubviews
Runloop相关
view的drawRect:方法
ViewController生命周期
加载流程

%title插图%num

1 1.init或者initWithCoder:(NSCoder *)aDecoder:(如果使用storyboard或者xib)
2 2.loadView:加载view
3 3.viewDidLoad:view加载完毕
4 4.viewWillAppear:控制器的view将要显示
5 5.viewWillLayoutSubviews:控制器的view将要布局子控件
6 6.viewDidLayoutSubviews:控制器的view布局子控件完成
7 这期间系统可能会多次调用viewWillLayoutSubviews、viewDidLayoutSubviews俩个方法
8
9 7.viewDidAppear:控制器的view完全显示
10 8.viewWillDisappear:控制器的view即将消失的时候
11 这期间系统也会调用viewWillLayoutSubviews 、viewDidLayoutSubviews 两个方法
12
13 9.viewDidDisappear:控制器的view完全消失的时候

didReceiveMemoryWarning

Discussion Your app never calls this method directly. Instead, this
method is called when the system determines that the amount of
available memory is low.

You can override this method to release any additional memory used by
your view controller. If you do, your implementation of this method
must call the super implementation at some point.

当app收到内存警告的时候会发消息给视图控制器。
app从来不会直接调用这个方法,而是当系统确定可用内存不足的时候采取调用。
如果你想覆写这个方法来释放一些控制器使用的额外内存,你应该在你的实现方法中调用父类的实现方法。

View的layoutSubviews
init初始化不会触发layoutSubviews。
addSubview会触发layoutSubviews。
改变一个UIView的frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化。
滚动一个UIScrollView引发UIView的重新布局会触发layoutSubviews。
旋转Screen会触发父UIView上的layoutSubviews事件。
直接调用setNeedsLayout 或者 layoutIfNeeded。

Runloop相关
在非主页面加载时

1 * thread #1, queue = ‘com.apple.main-thread’, stop reason = breakpoint 1.1
2   * frame #0: 0x0000000100529264 GSWatermarkView`-[GSWaterMarkView layoutSubviews](self=0x000000011d801410, _cmd=”layoutSubviews”) at GSWaterMarkView.m:110
3     frame #1: 0x00000001a77db5b0 UIKitCore`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2156
4     frame #2: 0x00000001a2fe7af0 libobjc.A.dylib`-[NSObject performSelector:withObject:] + 68
5     frame #3: 0x00000001a9d81c0c QuartzCore`-[CALayer layoutSublayers] + 292
6     frame #4: 0x00000001a9d81f14 QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 484
7     frame #5: 0x00000001a9d953fc QuartzCore`CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 140
8     frame #6: 0x00000001a9cda184 QuartzCore`CA::Context::commit_transaction(CA::Transaction*, double) + 296
9     frame #7: 0x00000001a9d05228 QuartzCore`CA::Transaction::commit() + 684
10     frame #8: 0x00000001a7362d6c UIKitCore`_afterCACommitHandler + 144
11     frame #9: 0x00000001a324bf5c CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 36
12     frame #10: 0x00000001a3246bfc CoreFoundation`__CFRunLoopDoObservers + 420
13     frame #11: 0x00000001a32471ac CoreFoundation`__CFRunLoopRun + 1292
14     frame #12: 0x00000001a3246978 CoreFoundation`CFRunLoopRunSpecific + 480
15     frame #13: 0x00000001ad376534 GraphicsServices`GSEventRunModal + 108
16     frame #14: 0x00000001a7338f0c UIKitCore`UIApplicationMain + 1940
17     frame #15: 0x000000010052814c GSWatermarkView`main(argc=1, argv=0x000000016f8df940) at main.m:14
18     frame #16: 0x00000001a30c6f04 libdyld.dylib`start + 4

在初始界面加载时

1 * thread #1, queue = ‘com.apple.main-thread’, stop reason = breakpoint 1.1
2   * frame #0: 0x0000000100b05264 GSWatermarkView`-[GSWaterMarkView layoutSubviews](self=0x000000010130f210, _cmd=”layoutSubviews”) at GSWaterMarkView.m:110
3     frame #1: 0x00000001a77db5b0 UIKitCore`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2156
4     frame #2: 0x00000001a2fe7af0 libobjc.A.dylib`-[NSObject performSelector:withObject:] + 68
5     frame #3: 0x00000001a9d81c0c QuartzCore`-[CALayer layoutSublayers] + 292
6     frame #4: 0x00000001a9d81f14 QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 484
7     frame #5: 0x00000001a9d953fc QuartzCore`CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 140
8     frame #6: 0x00000001a9cda184 QuartzCore`CA::Context::commit_transaction(CA::Transaction*, double) + 296
9     frame #7: 0x00000001a9d05228 QuartzCore`CA::Transaction::commit() + 684
10     frame #8: 0x00000001a7350d20 UIKitCore`__34-[UIApplication _firstCommitBlock]_block_invoke_2 + 84
11     frame #9: 0x00000001a324c95c CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 28
12     frame #10: 0x00000001a324c0e0 CoreFoundation`__CFRunLoopDoBlocks + 268
13     frame #11: 0x00000001a32470e0 CoreFoundation`__CFRunLoopRun + 1088
14     frame #12: 0x00000001a3246978 CoreFoundation`CFRunLoopRunSpecific + 480
15     frame #13: 0x00000001ad376534 GraphicsServices`GSEventRunModal + 108
16     frame #14: 0x00000001a7338f0c UIKitCore`UIApplicationMain + 1940
17     frame #15: 0x0000000100b0414c GSWatermarkView`main(argc=1, argv=0x000000016f303940) at main.m:14
18     frame #16: 0x00000001a30c6f04 libdyld.dylib`start + 4

可以看出在app启动时,初始界面View的layoutSubviews由__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__触发,后续的界面由__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__触发

view的drawRect:方法
直接调用setNeedsDisplay,或者setNeedsDisplayInRect:触发drawRect:,但是有个前提条件是rect大小不能为0。
drawRect的调用时机是在viewWillAppear和viewDidAppear之间。且在View的layoutSubviews之后

1 2020-03-03 14:05:58.384185+0800 GSWatermarkView[1318:1216023]  ViewController [-[ViewController loadView]]
2 2020-03-03 14:05:58.384252+0800 GSWatermarkView[1318:1216023]  ViewController [-[ViewController viewDidLoad]]
3 2020-03-03 14:05:58.385593+0800 GSWatermarkView[1318:1216023]  GSWaterMarkView [-[GSWaterMarkView didMoveToSuperview]]
4 2020-03-03 14:05:58.385686+0800 GSWatermarkView[1318:1216023]  ViewController [-[ViewController viewWillAppear:]]
5 2020-03-03 14:05:58.387915+0800 GSWatermarkView[1318:1216023]  ViewController [-[ViewController viewWillLayoutSubviews]]
6 2020-03-03 14:05:58.387956+0800 GSWatermarkView[1318:1216023]  ViewController [-[ViewController viewDidLayoutSubviews]]
7 2020-03-03 14:05:58.387975+0800 GSWatermarkView[1318:1216023]  GSWaterMarkView [-[GSWaterMarkView layoutSubviews]]
8 2020-03-03 14:05:58.388046+0800 GSWatermarkView[1318:1216023]  GSWaterMarkView [-[GSWaterMarkView drawRect:]]
9 2020-03-03 14:05:58.427785+0800 GSWatermarkView[1318:1216023]  ViewController [-[ViewController viewDidAppear:]]

调用sizeToFit,会触发drawRect的调用。
通过设置contentMode属性值为UIViewContentModeRedraw。那么将在每次设置或更改frame的时候自动调用drawRect:。
app启动时,添加到初始界面的堆栈,还是CALayer触发

iOS开发-逆向注入SDK之MonkeyDev注入打包

文章目录
MonkeyDev
使用
注入SDK
MonkeyDev
强大的工具集,MonkeyDev ,使用它行了!

安装教程见 Wiki

使用
拿着之前通过 frida砸壳 的 ipa包,先创建一个 MonkeyDev 工程。这里以 qqmusic 为例

%title插图%num
将砸壳的 ipa 放到 qqmusic/TargetApp/ 下,然后拖拽至工程文件中。

设置主工程的证书,dylib的不用设置

%title插图%num

提示 Showing All Messages Signing for “qqmusicDylib” requires a development team. Select a development team in the Signing & Capabilities editor. ,此时选择 qqmusicDylib->Build Settings->Add User-Defined Setting

%title插图%num

添加 CODE_SIGNING_ALLOWED 为 NO,再运行即可。

file not found: /usr/lib/libstdc++.dylib 问题

原因是新版本xcode去掉了libstdc++这个库,从老版本复制过来即可,这里直接使用别人的 https://github.com/devdawei/libstdc-

注入SDK
可以运行之后,我们在工程中初始化pod,

1 修改pod文件,注释use_frameworks!
2 # platform :ios, ‘9.0’
3
4 target ‘qqmusic’ do
5   # Comment the next line if you don’t want to use dynamic frameworks
6   # use_frameworks!
7   pod ‘GrowingAnalytics-cdp/Autotracker’
8   # Pods for qqmusic
9
10 end
11
12 target ‘qqmusicDylib’ do
13   # Comment the next line if you don’t want to use dynamic frameworks
14   # use_frameworks!
15   pod ‘GrowingAnalytics-cdp/Autotracker’
16   # Pods for qqmusicDylib
17
18 end

查找对应的appdelegate类,使用class-dump命令
class-dump -H xxx.app -o yourDir/Headers
1
发现其 AppDelegate 类叫 XXXXAppDelegate

然后使用logos注入SDK初始化代码,使用文档查看官网 http://iphonedevwiki.net/index.php/Logos

%title插图%num

1 // See http://iphonedevwiki.net/index.php/Logos
2
3 #import <UIKit/UIKit.h>
4 #import “GrowingAutotracker.h”
5
6 static NSString *const kGrowingProjectId = @”91eaf9b283361032″;
7
8 %hook XXXXAppDelegate
9
10 – (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
11         BOOL result = %orig;
12     GrowingTrackConfiguration *configuration = [GrowingTrackConfiguration configurationWithProjectId:kGrowingProjectId];
13     configuration.debugEnabled = YES;
14     configuration.impressionScale = 1.0;
15     configuration.dataCollectionServerHost = @”https://run.mocky.io/v3/08999138-a180-431d-a136-051f3c6bd306″;
16     [GrowingAutotracker startWithConfiguration:configuration launchOptions:launchOptions];
17         return result;
18 }
19
20 %end

然后再编译运行,至此,已经可以在App中调试SDK,并有相关日志输出了。

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