[iOS] 七七八八的小姿勢(shì)(5)

目錄:

  1. 手動(dòng)下載遠(yuǎn)程庫(kù)來(lái)pod install / pod update
  2. app在后臺(tái)時(shí)keyboard監(jiān)聽(tīng)也會(huì)被觸發(fā)
  3. 淘口令
  4. NSCopying實(shí)現(xiàn)
  5. 如何讓alert顯示在頂層
  6. 自帶emoji的行間距問(wèn)題
  7. app如何換色(清明黑白灰)
  8. UIApplicationDidBecomeActiveNotification
  9. viewDidLoad觸發(fā)

1. 手動(dòng)下載遠(yuǎn)程庫(kù)來(lái)pod install / pod update

遠(yuǎn)程辦公最怕的就是庫(kù)版本發(fā)生變化,最近一拉最新代碼經(jīng)常就要pod install / pod repo update,每次都會(huì)卡死總要有各種問(wèn)題,解決的方法大概就是github源就用4G丐怯,Google源就用代理+wifi哎垦,但是仍舊有的時(shí)候下不下來(lái)似袁,于是我就在這里說(shuō)一下如何直接從github下載然后讓pod過(guò)去统屈。

首先驱证,如果是卡在了pod repo update躏仇,也就是從遠(yuǎn)端拿這些庫(kù)最新的地址tag之類的恋脚,這個(gè)時(shí)候可以讓能夠過(guò)這一步的同事把/Users/用戶名/.cocoapods/repos/trunk/Specs整個(gè)文件夾壓縮打包發(fā)給你,直接替換就好焰手,這樣就可以成功的過(guò)update那關(guān)啦糟描。

如果木有同事裝好,可以直接從git上下載最新的:
https://github.com/CocoaPods/Specs

Specs里面存了哪些東西呢书妻?我們以一會(huì)兒想要實(shí)驗(yàn)的庫(kù)libwebp為例吧:


libwebp的各個(gè)版本

其實(shí)里面就是各個(gè)版本有個(gè)json以及json tag文件船响,我們打開(kāi)json看一下:

{
  "name": "libwebp",
  "version": "1.1.0",
  "summary": "Library to encode and decode images in WebP format.",
  "homepage": "https://developers.google.com/speed/webp/",
  "authors": "Google Inc.",
  "license": {
    "type": "BSD",
    "file": "COPYING"
  },
  "source": {
    "git": "https://chromium.googlesource.com/webm/libwebp",
    "tag": "v1.1.0"
  },
  "compiler_flags": "-D_THREAD_SAFE",
  "requires_arc": false,
  "platforms": {
    "osx": "10.8",
    "ios": "6.0",
    "tvos": "9.0",
    "watchos": "2.0"
  },
  "pod_target_xcconfig": {
    "USER_HEADER_SEARCH_PATHS": "$(inherited) ${PODS_ROOT}/libwebp/ ${PODS_TARGET_SRCROOT}/"
  },
  "preserve_paths": "src",
  "default_subspecs": [
    "webp",
    "demux",
    "mux"
  ],
  "prepare_command": "sed -i.bak 's/<inttypes.h>/<stdint.h>/g' './src/webp/types.h'",
  "subspecs": [
    {
      "name": "webp",
      "source_files": [
        "src/webp/decode.h",
        "src/webp/encode.h",
        "src/webp/types.h",
        "src/webp/mux_types.h",
        "src/webp/format_constants.h",
        "src/utils/*.{h,c}",
        "src/dsp/*.{h,c}",
        "src/dec/*.{h,c}",
        "src/enc/*.{h,c}"
      ],
      "public_header_files": [
        "src/webp/decode.h",
        "src/webp/encode.h",
        "src/webp/types.h",
        "src/webp/mux_types.h",
        "src/webp/format_constants.h"
      ]
    },
    {
      "name": "demux",
      "dependencies": {
        "libwebp/webp": [

        ]
      },
      "source_files": [
        "src/demux/*.{h,c}",
        "src/webp/demux.h"
      ],
      "public_header_files": "src/webp/demux.h"
    },
    {
      "name": "mux",
      "dependencies": {
        "libwebp/demux": [

        ]
      },
      "source_files": [
        "src/mux/*.{h,c}",
        "src/webp/mux.h"
      ],
      "public_header_files": "src/webp/mux.h"
    }
  ]
}

然后我們就可以去source的git下載相應(yīng)tag的庫(kù)啦

"source": {
  "git": "https://chromium.googlesource.com/webm/libwebp",
  "tag": "v1.1.0"
},
git庫(kù)

下載tar.gz或者zip都OK,然后解壓放到我們project的本地pod里面:


工程里面的pod目錄

注意哦你放進(jìn)去的就是你從庫(kù)倉(cāng)庫(kù)下載下來(lái)的文件,可能和你看到本地這個(gè)庫(kù)的內(nèi)容不一樣见间,沒(méi)關(guān)系的聊闯,你放進(jìn)去再pod install過(guò)了以后就一樣啦。

現(xiàn)在我們實(shí)現(xiàn)了下載需要的版本米诉,并放入本地緩存菱蔬,之后就可以來(lái)看如何pod install啦。在pod install的過(guò)程中史侣,其實(shí)它就是比較了Podfile.lock文件和本地緩存文件版本差異拴泌,如果有區(qū)別就去遠(yuǎn)端下載,所以現(xiàn)在我們需要讓本地緩存的庫(kù)和podfile.lock里面一致抵窒,當(dāng)然有一種方法是你把podfile.lock里面的庫(kù)版本降低到你本地的版本弛针,這樣你也不用從遠(yuǎn)端下載就可以成功pod install啦叠骑,只是這樣的話你需要經(jīng)常stash著這個(gè)變化李皇。

那么本地緩存的版本由什么管理呢?其實(shí)就是項(xiàng)目/Pods/Manifest.lock文件宙枷,你打開(kāi)會(huì)發(fā)現(xiàn)和Podfile.lock文件非常一致掉房,只要把自己替換的庫(kù)例如libwebp相關(guān)的內(nèi)容都從Podfile.lock拷到項(xiàng)目/Pods/Manifest.lock即可,如果Podfile.lock里面的版本不是最新的慰丛,你就手動(dòng)改一下版本號(hào)以及spec checksum即可卓囚。

可參考:http://www.reibang.com/p/06f507d2987d

例如podfile.lock里需要改成醬紫,manifest.lock必須相關(guān)的和podfile.lock保持一致诅病,包括checksum的編號(hào):

  - libwebp (1.1.0):
    - libwebp/demux (= 1.1.0)
    - libwebp/mux (= 1.1.0)
    - libwebp/webp (= 1.1.0)
  - libwebp/demux (1.1.0):
    - libwebp/webp
  - libwebp/mux (1.1.0):
    - libwebp/demux
  - libwebp/webp (1.1.0)

SPEC CHECKSUMS:
  ……
  KVOController: d72ace34afea42468329623b3379ab3cd1d286b6
  libwebp: 946cb3063cea9236285f7e9a8505d806d30e07f3

那么CHECKSUMS的編號(hào)是如何生成的呢哪亿?我最開(kāi)始以為是遠(yuǎn)程倉(cāng)庫(kù)的commit號(hào),后來(lái)查了一下看到上面的refer文章才知道是這么生成的:

pod ipc spec /Users/用戶名/.cocoapods/repos/trunk/Specs/1/9/2/libwebp/1.1.0/libwebp.podspec.json  | openssl sha1
946cb3063cea9236285f7e9a8505d806d30e07f3

然后你再pod install就可以成功了吼~ (P.S. 想要知道自己卡在哪里贤笆,加上--verbose就可以啦)


2. app在后臺(tái)時(shí)keyboard監(jiān)聽(tīng)也會(huì)被觸發(fā)

這個(gè)問(wèn)題是我昨天晚上QA小姐姐發(fā)現(xiàn)的蝇棉,就是如果我們注冊(cè)了observer監(jiān)聽(tīng)UIKeyboardDidHideNotification以及UIKeyboardWillShowNotification,那么即使我們的app在后臺(tái)芥永,當(dāng)我們?cè)谄渌鸻pp例如微信里面調(diào)用了鍵盤篡殷,自己app里面監(jiān)聽(tīng)keyboard的方法仍舊會(huì)被觸發(fā),這樣在兩個(gè)app來(lái)回切換并且有微信鍵盤的時(shí)候就看著很奇怪埋涧。

于是我Google了一下 (https://stackoverflow.com/questions/34409566/keyboardwillshow-gets-called-for-other-apps-keyboards)板辽,解決方案就是在監(jiān)聽(tīng)觸發(fā)的handler函數(shù)里面最好先判斷自己的app是不是active的,如果不是就return不去處理這個(gè)監(jiān)聽(tīng):

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShowNotificationHandler) name:UIKeyboardWillShowNotification object:nil];

- (void) keyboardWillShowNotificationHandler {
  if ([[UIApplication sharedApplication] applicationState] != UIApplicationStateActive) {
    return;
  }
  ……
}

3. 淘口令

各種復(fù)制口令到app然后會(huì)打開(kāi)一個(gè)頁(yè)面棘催,最早感覺(jué)就是淘寶這么做的劲弦,它的是咋實(shí)現(xiàn)的呢?first step是從你的剪貼板拿到你復(fù)制的東西醇坝,second step我猜是把那串神奇的字符串發(fā)給后端瓶您,我們只要pop up一個(gè)webview,內(nèi)容后端會(huì)來(lái)填充頁(yè)面。

所以我們先來(lái)看一下從剪貼板拿你的magic string:

// 程序進(jìn)入前臺(tái)
-(void)applicationWillEnterForeground:(UIApplication*)application {
  UIPasteboard* pasteboard= [UIPasteboard generalPasteboard];
  NSLog(@"pasteboard: %@", pasteboard.string);
}

我拿拼多多的app來(lái)fake了一下呀袱,然后復(fù)制了一個(gè)口令打開(kāi)拼多多看到的頁(yè)面層級(jí)是這樣的:(神奇的發(fā)現(xiàn)陌陌的反fake比拼多多做的好贸毕。。夜赵。


口令拼多多頁(yè)面層級(jí)

所以彈出的頁(yè)面是原生的不是web哈~

但是如果你無(wú)網(wǎng)復(fù)制粘貼進(jìn)拼多多就沒(méi)有反應(yīng)明棍,所以雖然不是直接pop一個(gè)web讓后端做,但應(yīng)該是從剪貼板拿到string以后發(fā)給了后端寇僧,后端會(huì)告訴前端彈哪種view摊腋,并把需要的填充數(shù)據(jù)返還。


4. NSCopying實(shí)現(xiàn)

NSCopying的實(shí)現(xiàn)我們需要把屬性一個(gè)一個(gè)的賦值就很煩嘁傀,如果增加了新的屬性還得手動(dòng)記得改NSCopying兴蒸,如果忘了就有可能犯錯(cuò)。

所以其實(shí)比較靠譜的是利用runtime细办,獲取所有屬性橙凳,然后賦值:

+ (nonnull id)copyObject:(nonnull NSObject *)object
{
    Class clazz = [object class];
    id objCopy = [[clazz alloc] init];
    u_int count;
    objc_property_t *properties = class_copyPropertyList(clazz, &count);
    for (int i = 0; i < count ; i++) {
        const char* propertyName = property_getName(properties[I]);
        NSString *name = [NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding];
        id value = [object valueForKey:name];
        if([value respondsToSelector:@selector(copyWithZone:)]) {
            [objCopy setValue:[value copy] forKey:name];
        } else if (value != nil) {
            [objCopy setValue:value forKey:name];
        }
    }
    free(properties);

    return objCopy;
}

然后如果有些屬性比較特殊,你可以再單獨(dú)處理一下~


5. 如何讓alert顯示在頂層

我們有個(gè)需求要在webview上面顯示一個(gè)alert笑撞,但是如果拿topVC是nil岛啸,所以不能present alert。

如果我們想搞個(gè)alert在任何時(shí)候都能顯示到最頂層可以這么搞茴肥,繼承UIAlertController:

@interface TopLiveAlertController ()

@property (nonatomic, weak) UIWindow *previousKeyWindow;
@property (nonatomic, strong) UIWindow *alertContainerKeyWindow;

@end

@implementation TopLiveAlertController

- (void)viewDidLoad {
    [super viewDidLoad];
}

- (void)showInTop {
    self.previousKeyWindow = [UIApplication sharedApplication].keyWindow;
    [self.alertContainerKeyWindow removeFromSuperview];
    self.alertContainerKeyWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.alertContainerKeyWindow.rootViewController = [UIViewController new];
    self.alertContainerKeyWindow.windowLevel = UIWindowLevelAlert + 1;
    [self.alertContainerKeyWindow makeKeyAndVisible];
    [self.alertContainerKeyWindow.rootViewController presentViewController:self animated:YES completion:nil];
}

- (void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion {
    [super dismissViewControllerAnimated:flag completion:completion];
    
    [self.alertContainerKeyWindow removeFromSuperview];
    self.alertContainerKeyWindow = nil;
    [self.previousKeyWindow makeKeyAndVisible];
}

@end
  • 這里牽扯到一個(gè)小問(wèn)題坚踩,windowLevel是啥?

關(guān)于UIWindow可以參考一下這個(gè)http://www.reibang.com/p/1c2ac0fa2e4a

其實(shí)windowLevel就是window的z軸瓤狐,默認(rèn)都是UIWindowLevelNormal (0)的:

UIKIT_EXTERN const UIWindowLevel UIWindowLevelNormal;
UIKIT_EXTERN const UIWindowLevel UIWindowLevelAlert;
UIKIT_EXTERN const UIWindowLevel UIWindowLevelStatusBar API_UNAVAILABLE(tvos);

6. 自帶emoji的行間距問(wèn)題

參考:http://www.reibang.com/p/715181fbc28b

這個(gè)又是一個(gè)很煩人的問(wèn)題瞬铸,就是我們正常的文字如果用YYTextLayout *textLayout = [YYTextLayout layoutWithContainer:container text:attributeString];獲取高度完全木有問(wèn)題,例如一個(gè)14font的文字可能計(jì)算完的高度是16础锐,但是如果這行包括了emoji嗓节,這行的高度可能算出來(lái)就是24了。

于是如果我們的聊天氣泡的高度是根據(jù)計(jì)算出啦的行高+上下間距來(lái)定的高度郁稍,就會(huì)出現(xiàn)在有emoji的時(shí)候行高突然變多赦政。這個(gè)問(wèn)題我實(shí)在很頭疼,所以換了個(gè)方法來(lái)做耀怜,我們嘗試固定行高恢着,然后不加邊距。這樣其實(shí)無(wú)論是文字還是文字&emoji都要放進(jìn)一樣的高的container~

類似醬紫:

YYTextLinePositionSimpleModifier *modifier = [YYTextLinePositionSimpleModifier new];
 modifier.fixedLineHeight = 24;
     
YYTextContainer *container = [YYTextContainer new];
container.size = CGSizeMake(constrainedWidth, 10000);
container.linePositionModifier = modifier;
     
YYTextLayout *textLayout = [YYTextLayout layoutWithContainer:container text:attributeString];
return CGSizeMake(textLayout.textBoundingSize.width, textLayout.textBoundingSize.height);

但加入了emoji以后的基線偏移我就實(shí)在解決不了了頭禿财破。掰派。


7. app如何換色(清明黑白灰)

這個(gè)就和我之前好像寫過(guò)一個(gè)主題換色是一個(gè)道理,就也是把顏色都寫到配置文件左痢,然后用啥就用它的key靡羡。但這個(gè)注意UI千萬(wàn)得規(guī)定一個(gè)用色標(biāo)準(zhǔn)系洛、按小哥哥的說(shuō)法就是色庫(kù),要不就很麻煩每次得自己加很多顏色的key value略步。描扯。。


8. UIApplicationDidBecomeActiveNotification

這個(gè)通知大家都很熟悉了趟薄,當(dāng)app的狀態(tài)變?yōu)閍ctive就會(huì)收到绽诚,一個(gè)很熟悉的場(chǎng)景就是我們退到后臺(tái)以及回到前臺(tái)。

但是有一個(gè)比較特殊杭煎,在iOS13的時(shí)候如果我們app已經(jīng)在前臺(tái)恩够,用戶下拉通知欄可以看到其他app的push,這個(gè)時(shí)候會(huì)先resign active羡铲,在become active蜂桶,即使用戶還沒(méi)回到我們app,還在專心的讀push也切。

但是如果你下拉的是右上角的工具欄(有手電筒扑媚、亮度等),則只會(huì)resign active贾费,當(dāng)你上滑把工具欄收起再次看到app的時(shí)候才會(huì)become active钦购。

App的各種狀態(tài)可以參考:http://www.reibang.com/p/ee4add97c96a檐盟,經(jīng)常會(huì)搞不清background和resign active褂萧,其實(shí)就是從active到inactive會(huì)發(fā)resign active通知,如果從inactive到background則是enter background通知葵萎。


9. viewDidLoad觸發(fā)

我以前一直以為viewDidLoad是只有頁(yè)面最開(kāi)始出現(xiàn)的時(shí)候才會(huì)觸發(fā)导犹,但是這周遇到一個(gè)問(wèn)題是當(dāng)VC都快銷毀的時(shí)機(jī)還出發(fā)了viewDidLoad,然后看堆棧是由于VC的getView方法被調(diào)用了羡忘。

但不是每次你調(diào)用vc.view就會(huì)執(zhí)行viewDidLoad哦谎痢,聽(tīng)起來(lái)也很奇怪,應(yīng)該是懶加載的卷雕,因?yàn)樯蟼€(gè)場(chǎng)景可能view已經(jīng)被銷毀了节猿,或者VC剛初始化你就調(diào)用了他的view,所以當(dāng)VC的view第一次nil被讀取的時(shí)候就會(huì)觸發(fā)viewDidLoad吼漫雕。

viewDidLoad調(diào)用棧
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末滨嘱,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子盏触,更是在濱河造成了極大的恐慌舒岸,老刑警劉巖验夯,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異囊扳,居然都是意外死亡吩翻,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門锥咸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)狭瞎,“玉大人,你說(shuō)我怎么就攤上這事搏予〗抛鳎” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵缔刹,是天一觀的道長(zhǎng)球涛。 經(jīng)常有香客問(wèn)我,道長(zhǎng)校镐,這世上最難降的妖魔是什么亿扁? 我笑而不...
    開(kāi)封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮鸟廓,結(jié)果婚禮上从祝,老公的妹妹穿的比我還像新娘。我一直安慰自己引谜,他們只是感情好牍陌,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著员咽,像睡著了一般毒涧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上贝室,一...
    開(kāi)封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天契讲,我揣著相機(jī)與錄音,去河邊找鬼滑频。 笑死捡偏,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的峡迷。 我是一名探鬼主播银伟,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼绘搞!你這毒婦竟也來(lái)了彤避?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤看杭,失蹤者是張志新(化名)和其女友劉穎忠藤,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體楼雹,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡模孩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年尖阔,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片榨咐。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡介却,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出块茁,到底是詐尸還是另有隱情齿坷,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布数焊,位于F島的核電站永淌,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏佩耳。R本人自食惡果不足惜遂蛀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望干厚。 院中可真熱鬧李滴,春花似錦、人聲如沸蛮瞄。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)挂捅。三九已至芹助,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間籍凝,已是汗流浹背周瞎。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工苗缩, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留饵蒂,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓酱讶,卻偏偏與公主長(zhǎng)得像退盯,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子泻肯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容