# 常见问题

### 1. GrowingIO SDK无埋点采集的原理是什么？

实现原理：[Method Swizzling](http://nshipster.cn/method-swizzling/) ( method swizzling 作用为替换或者修改系统方法)，可理解为以下 5 个步骤。

1. 在系统方法M1中插入GIO代码GIO\_B1
2. 系统方法 M1 被执行，此时也会执行 GIO\_B1
3. 在 GIO\_B1 内遍历 View Tree / DOM Tree 以及 UIViewController 的层次关系以获取必要的数据
4. 生成待发送事件并缓存
5. 发送事件到服务器，完成采集

### 2. GrowingIO SDK 支持哪些iOS系统？

目前支持iOS 8-iOS 13。

### 3. 如果动态添加UIView、删除UIView或者修改UIView在父视图中的位置，会有什么影响？

SDK 依赖 subviews 里面的元素次序。如果有动态的需求，建议在 viewDidLoad 里加载所有可能的 UIView 节点，添加或删除可以通过设置 hidden 属性来实现，把不需要显示的设置 hidden 属性为 YES，把需要显示的设置 hidden 属性为 NO。在 UIView 已经显示之后，不要调用 -bringSubviewToFront:方法， -sendSubviewToBack:方法或 -insertSubview: 方法。

### 4. 子线程操作UI引起的问题如何处理？

&#x20;答：GIO SDK 会在主线程中遍历找寻某个subView，如果此时在子线程中删除了该subView，就会造成错乱甚至 crash。此外，Apple 不建议用户在子线程更新 UI。建议客户在 Xcode 中打开 "Main Thread Checker" 检测线程使用是否合理。参考：[Main Thread Checker](https://developer.apple.com/documentation/code_diagnostics/main_thread_checker?language=objc)

### 5. 圈选时，来自不同VC的元素显示的VC名称相同？

这种情况，一般是因为父 VC 添加子 VC 方式不正确引起的，请客户排查子VC的生命周期是否完整。

### 6. 是否允许设置view的growingAttributesValue为单个的数字或者字母？

不允许这种设置。出于安全考虑，金融类 App 会自定义键盘（默认键盘容易被黑），如果 SDK 允许采集 V 值为单个数字或字母的点击事件，则有可能会记录用户输入的账号或密码。由于上述原因， SDK 不会发送V 值为单个字母或数字的点击事件，如果用户违反约定，则会导致某个元素只有浏览量而没有点击量。

### 7. 埋点为什么也要在主线程调用？

埋点采集UI操作，建议在UI线程（主线程）中调用。

### 8. 是否支持在开启热图的时候圈选？

不支持，开启热图可能会导致被圈选元素的 x 值发生变化。

### 9. 是否支持用UITouch事件的点击事件？

不支持，建议使用 UITapGestureRecognizer

### 10. GIO SDK是否支持Swift项目？

支持

### 11. App做了Button防重复点击，集成SDK后发现按钮无法点击？

如果您的UIButton 防重复方案中， hook了 UIControl 的 originalSelector： `@selector(sendAction:to:forEvent:)` 方法，请确保在您的 swizzledSelector： `@selector(your_swizzled_sendAction:to:forEvent:)` 方法**前面**执行 如下代码：

```objectivec
- (void)your_swizzled_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
     
      //  Called before your  extra work
       if ([NSStringFromClass([target class]) isEqualToString:@"GrowingUIControlObserver"]) { 
              [self your_swizzled_sendAction:action to:target forEvent:event]; // call origin
              return;
       }

       // Do your extra work. such as judge click interval....

       [self your_swizzled_sendAction:action to:target forEvent:event]; // call origin
}
```

如果还是无法点击，请联系技术支持。

### 12. 如果项目中使用了Firebase SDK，需要注意什么？

如果您的iOS项目中集成了Firebase SDK，请确保使用的Firebase SDK版本在4.8.1及以上，否则会造成数据采集不到的情况。

当您的Firebase SDK版本符合要求，但是没有发送vst事件时，请将采集模式改为hook模式。

修改方法：

Objective-C：修改main.m文件：

![](https://2602900487-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lo08UtW7H58ehFKeZ4g%2F-LwCCuMmDeSgcT4rdIXZ%2F-LwCMguzbCTL5Uc6XU8m%2Fimage.png?alt=media\&token=7a73ef61-9b42-45b2-a0e6-4c0b24935253)

Swift：修改AppDelegate.swift，并手动创建main.swift文件。

![](https://2602900487-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lo08UtW7H58ehFKeZ4g%2F-LwCCuMmDeSgcT4rdIXZ%2F-LwCMyp2DW6e35LclH_I%2Fimage.png?alt=media\&token=dc46a804-6bb1-4850-bf3d-a9b3efba40be)

![](https://2602900487-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lo08UtW7H58ehFKeZ4g%2F-LwCNDZ4vuB9fNGO2BFn%2F-LwCOW_i36hO_QhDggkv%2Fimage.png?alt=media\&token=5f62943f-0f9e-4368-86dc-1da56afab6bf)

### 13. 关于苹果隐私政策相关事宜的公告

亲爱的客户：

您好！

&#x20;从2018年10月3日开始，App Store Connect将要求所有新应用和应用更新版本时提供**隐私政策**，添加后才可以在App Store上提交或通过TestFlight外部测试进行分发。

【苹果通知：As a reminder, in June the App Store Review Guidelines were updated to require a privacy policy for all new apps and app updates as part of the app review process. Starting October 3, 2018, App Store Connect will require a privacy policy for all new apps and app updates before they can be submitted for distribution on the App Store or through TestFlight external testing. In addition, your app’s privacy policy link or text will only be editable when you submit a new version of your app.（详情可参见：[https://developer.apple.com/news/?id=08312018a](https://developer.apple.com/news/?id=08312018a%EF%BC%89%E3%80%82) ）

所以，在此提醒各位开发者：**提交App Store 审核前一定要准备自己的隐私权政策，并在app SafariViewContoller中弹出，否则会无法通过审核哦！如需要专业的法律意见，还请各位开发者小伙伴咨询您的律师或法律顾问哦！**

### **14. Webview crash**

**如果遇到此类崩溃:`Cannot form weak reference to instance (xxxxx) of class xxxxxx. It is possible that this object was over-released, or is in the process of deallocation`** **或者程序卡死通过 bt 打印出的堆栈含有`weak_register_no_lock`并且错误是关于`UIWebView+Growing`的。** 解释如下: 由于业务需要我们会 hook `UIWebView` 的 `setDelegate` 方法 拿到传入的对象从而进行对`UIWebViewDelegate` 一系列方法的监听，并且对传入的对象实现 `weak` 处理,这样做是为了保证不影响客户对象的引用计数； 由于苹果 api 的不完善 `UIWebViewDelegate` 的声明至今为`assign，`所以`delegate`对象在释放后不会被置为`nil`;由此可能会造成的后果是`setDelegate`方法调用时，如果传入的是一个`over-released`, or is in the process of deallocation 的对象而我们 SDK 又对此对象进行了 `weak` 处理,从而导致崩溃；

由于苹果api没有判断对象是否是over-released, or is in the process of deallocation的 api ，所以我们SDK暂时无法处理。需要手动解决一下，解决方式很简单，先分享一个发生崩溃的案例：

**案例如下:** 这是客户UIWebViewDelegate对象中dealloc方法

```java
- (void)dealloc
{
    self.webView.delegate = nil;
}
```

上面的代码引发了崩溃,很多人奇怪delegate不是已经设置为nil了么? 为什么还崩，请看下面是如何解决的

```java
- (void)dealloc
{
    _webView.delegate = nil;
}
```



发现差异了么？我们没有调用的`webView`的`get`方法，因为在此案例中`webView`的`get`方法会提前执行一遍`setDelegate`方法从而导致崩溃。 所以希望您在`delegate`对象的`dealloc`方法中不要调用`webView`的`get`方法即`self.webView`，而是采用`_webView`的形式把`delegate`设置为`nil`。

在实际开发中，除了上述场景之外，还有如下两种情况：

* `UIWebViewDelegate` 对象是自定义的 `UIWebView` 本身，通过上述方式会发现在自定义的 `UIWebView` 类中无法通过下划线的方式来访问 `delegate` 属性，即 `_delegate`，因此也就无法调用 `_delegate = nil；`解决方式如下：

```java
-（void）dealloc 
{
        @autoreleasepool {
        self.growingAttributesDonotTrack = YES;
    }
    self.delegate = nil;
}
```

如果在其他的第三方SDK中发生了这样的问题，但是无法修改其源码的情况下，可以按照如下方式进行处理，首先根据崩溃信息找到崩溃产生的类名信息，例如

```java
Cannot form weak reference to instance (0xXXXXX) of class NSKVONotifying_XXUIWebView
```

`XXUIWebView` 即为自定义的 `UIWebView` 类， 此时可以新增一个UIView的分类，具体实现代码如下，特别需要注意的是 `Class clazz = NSClassFromString(@"XXUIWebView");`

```java
#import "UIView+Growing_fix.h"
#import <objc/runtime.h>
#import "Growing.h"
@implementation UIView (Growing_fix)
+(void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class clazz = NSClassFromString(@"XXUIWebView");
        
        SEL originalSelector = NSSelectorFromString(@"dealloc");
        SEL swizzledSelector = @selector(grow_dealloc);
        
        Method originalMethod = class_getInstanceMethod(clazz, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(clazz, swizzledSelector);
        
        BOOL didAddMethod =
        class_addMethod(clazz,
                        originalSelector,
                        method_getImplementation(swizzledMethod),
                        method_getTypeEncoding(swizzledMethod));
        
        if (didAddMethod) {
            class_replaceMethod(clazz,
                                swizzledSelector,
                                method_getImplementation(originalMethod),
                                method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    });
}
​
- (void)grow_dealloc
{
    @autoreleasepool {
        self.growingAttributeDonotTrack = YES;
    }
    [self grow_dealloc];
}
@end
```

备注:  SDK 2.8.12开始去除对UIWebView的支持
