開發問題集錦

1. init /initWithFrame方法的調用

系統會調用數組

2. 第三方庫重複

問題表現

duplicate symbol _OBJC_METACLASS_$_JKSerializer in:
    /Users/tony/Desktop/XXXProject/Lib/libMiPushSDK.a(JSONKit.o)
    /Users/tony/Library/Developer/Xcode/DerivedData/XXXProject-boqkajmzatzxohbyrrhklfiuknic/Build/Products/Debug-iphoneos/libPods.a(JSONKit.o)
ld: 24 duplicate symbols for architecture armv7
clang: error: linker command failed with exit code 1 (use -v to see invocation)

解決方式

  1. 找到第三方庫安全

  2. 進行復制副本app

  3. 查看包信息iphone

    `lipo -info libx.a`  
    針對多平臺須要逐一作解包重打包操做
  4. 建立臨時文件夾,用於存放armv7平臺解壓後的.o文件:mkdir armv7ide

  5. 取出armv7平臺的包:lipo libx.a -thin armv7 -output armv7/libx-armv7.a 佈局

  6. 查看庫中所包含的文件列表:ar -t armv7/libx-armv7.aui

  7. 解壓出object file(即.o後綴文件):cd armv7 && ar xv libx-armv7.aspa

  8. 找到衝突的包(JSONKit),刪除掉rm JSONKit.o線程

  9. 從新打包object file:cd .. && ar rcs libx-armv7.a armv7/*.o,能夠再次使用[2]中命令確認是否已成功將文件去除rest

  10. 將其餘幾個平臺(armv7s, i386)包逐一作上述[1-6]操做

  11. 從新合併爲fat file的.a文件:

    `lipo -create libx-armv7.a libx-armv7s.a libx-i386.a -output libMiPushSDK-new.a`
  12. 拷貝到項目中覆蓋源文件:

    `cp libMiPushSDK-new.a /Users/xxx/Desktop/XXXProject/Lib/libMiPushSDK.a`

3. 在使用UITableView 或者CollectionView 常常會出現因爲cell個數與數據源不等crash

這種問題主要出在cell 刷新次數頻繁的操做中,例如聊天界面接收與發送消息等操做

解決方式

  1. 經過一個數組,先接收數據,而後再講此數組添加到數據源中,刷新界面

[self.collectionView performBatchUpdates:^{
             //將臨時數組添加到數據源中
          [self.messsagesSource addObjectsFromArray:_subMessageDataSource];

          NSMutableArray *indexPaths = @[].mutableCopy;
          for (NSInteger i = _subMessageDataSource.count; i > 0 ; i--) {
              NSIndexPath *indexPath = [NSIndexPath indexPathForItem:(self.messsagesSource.count - i) inSection:0];
              [indexPaths addObject:indexPath];
          }
           [self.collectionView insertItemsAtIndexPaths:indexPaths];
            } completion:^(BOOL finished) {
                if (finished) {
                    [_subMessageDataSource removeAllObjects];
                }
            }];

4. 關於 NSTimer 形成沒法釋放問題

  1. 經過若引用來引用timer

    __weak id weakSelf = self;
     timer = [NSTimer scheduledTimerWithTimeInterval:30.0f target:weakSelf     selector:@selector(tick) userInfo:nil repeats:YES];
  2. 經過GCD 建立定時器

    __weak typeof(self) weakSelf = self;
    double delayInSeconds = 2.0;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)    (delayInSeconds * NSEC_PER_SEC));
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        [weakSelf doSomethingRepeatedly];
    });
    }
  3. 經過

    - (void)timer2 {
    
    NSMethodSignature *method = [ViewController instanceMethodSignatureForSelector:@selector(invocationTimeRun:)];
    
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:method];
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 invocation:invocation repeats:YES];
    
    // 設置方法調用者
    invocation.target = self;
    
    // 這裏的SEL須要和NSMethodSignature中的一致
    invocation.selector = @selector(invocationTimeRun:);
    
    // 設置參數
    // //這裏的Index要從2開始,覺得0跟1已經被佔據了,分別是self(target),selector(_cmd)
    // 若是有多個參數, 可依次設置3 4 5 ...
    [invocation setArgument:&timer atIndex:2];
    
    [invocation invoke];
    
    NSLog(@"start");
    }
  4. 經過GCD 實現

    • 實現延遲執行

      dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC);
       dispatch_after(delayTime, dispatch_get_main_queue(), ^(void){
           NSLog(@"延遲2s後執行");
       
       });
    • 基於延遲執行實現

      `void

      dispatch_source_set_timer(dispatch_source_t source,

    dispatch_time_t start,
    uint64_t interval,
    uint64_t leeway)` 主要是此方法

  • (void)gcdTimer1 {

    // 獲取全局隊列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // 建立定時器
    dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);

    // 開始時間
    dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC));

    // dispatch_time_t start = dispatch_walltime(NULL, 0);

    // 重複間隔
    uint64_t interval = (uint64_t)(1.0 * NSEC_PER_SEC);

    // 設置定時器
    dispatch_source_set_timer(_timer, start, interval, 0);

    // 設置須要執行的事件
    dispatch_source_set_event_handler(_timer, ^{

    //在這裏執行事件
    static NSInteger num = 0;
    
    NSLog(@"%ld", (long)num);
    num++;
    
    if (num > 4) {
        
        NSLog(@"end");
        
        // 關閉定時器
        dispatch_source_cancel(_timer);
    }

    });
    // 開啓定時器
    dispatch_resume(_timer);

    NSLog(@"start");
    }

5. 關於通話狀態界面向下移的問題

方式1: 經過監聽statusbar高度的變換,更新UI

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(layoutControllerSubViews) name:UIApplicationDidChangeStatusBarFrameNotification object:nil];

// 從新佈局
- (void)layoutControllerSubViews
{
    // 對須要的UI從新適配Frame
}

方法2: 在系統的viewDidLayoutSubviews方法中從新設置值

-(void) viewDidLayoutSubviews {
    [super viewDidLayoutSubviews]; 
    self.view.y = 0;
    self.view.height = ScreenHeght;
}

6. UISearchController 搜索框不見的緣由

self.definesPresentationContext = YES;

7. 自定義相機照片截取特定區域

可能拍攝的照片與看到的照片是不一樣的
![來自簡書]()

//_cameraView爲相機視圖,即拍攝時看到圖片的區域
CGFloat scale = image.size.width / _cameraView.width;//計算出縮放的比例
CGFloat showImageH = image.size.height / scale;//縮放後圖片的高度
CGFloat offsetY = (showImageH - _cameraView.height) * 0.5;//上下超出的部分是相等的,因此*0.5得出上面超過的部分

CGRect rect = CGRectMake(x, y, width,height);
CGImageRef tailorImageRef = CGImageCreateWithImageInRect(photo.CGImage, rect);
UIImage *tailorImage = [UIImage imageWithCGImage:tailorImageRef];

8. 判斷當前設備是iPhone仍是iPad

能夠經過系統給定的屬性進行判斷

if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
        //iPhone, present activity view controller as is
        [self presentViewController:activityViewController animated:YES completion:nil];
    }
    else
    {
        //iPad, present the view controller inside a popover
        if (![self.activityPopover isPopoverVisible]) {
            self.activityPopover = [[UIPopoverController alloc] initWithContentViewController:activityViewController];
            [self.activityPopover presentPopoverFromBarButtonItem:self.shareItem permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
        }
        else
        {
            //Dismiss if the button is tapped while pop over is visible
            [self.activityPopover dismissPopoverAnimated:YES];
        }
    }

9.iOS中可變對象的線程不安全問題

iOS開發中 (Objective-C) 中,可變對象廣泛都是線程不安全的, 這樣在操做是就容易形成一些莫名其妙的問題出現 , 好比: UICollectionView的cell與數據源不一樣步啊等問題

//添加鎖機制
    @synchronized(arrayM)
    {
        [arrayM addObject:profile];
    }
    
     @synchronized(arrayM) {
            [arrayM removeObject:profile];
    }

10. 針對須要傳入多個枚舉值的處理以及獲取傳入枚舉值

在開發中每每有時候須要往方法中傳入多個枚舉值,可是隻有一個參數, 須要經過__或運算__進行傳入,當須要獲取傳入的枚舉值時,須要經過__與運算__獲取

//或運算
int interestSet = SelectionKey.OP_READ | Selection.OP_WRITE;   

//與運算獲取值
boolean isInterestedInRead = interestSet & SelectionKey.OP_READ;
相關文章
相關標籤/搜索