iOS 工作遇到問題記錄


iOS 工作遇到問題記錄

 

1、UITableView的scrollDelegate問題

下午遇到一個奇怪的問題,之前都沒有注意過,由於A VC中要實現tableView和其他View位置的聯動,
所以實現了tableView的delegate中的scrollViewDidScroll方法,結果在點擊商品push 商品詳情VC B 的時候,問題出現了。

問題表現:
在調用[self.navigationController pushViewController:productDetailVC animated:YES];
時發現VC A中的tableView總是會滾動到頂部(contentOffset被修改了)

看了半天也沒發現問題,后面在scrollViewDidScroll的位置加了一個斷點,發現在navigationController在Push VC B的過程中,系統會調用一次VC A中tableView的scrollViewDidScroll方法,關鍵是這時調用中傳入的contentOffset是有問題的(0,-contentInset.y),所以導致了VC A中的tableView會自動返回頭部

解決方法:在VC A的viewWillDisappear的時候設置tableView的delegate為nil,同時在viewWillAppear中再把tableView的delegate設置回來,這個問題就被解決掉了。
all in all 問題很奇怪,希望大家不再被同樣的問題困擾

 

2、UIView的exclusiveTouch屬性

通過設置[selfsetExclusiveTouch:YES];可以達到同一界面上多個控件接受事件時的排他性,從而避免一些問題。

 

3、UIScrollView和UITableView嵌套時點擊statusBar,scrollView不反回頭部的問題

蘋果在UIScrollView頭文件的注釋可以清楚的解決我們的困惑

// When the user taps the status bar, the scroll view beneath the touch which is closest to the status bar will be scrolled to top, but only if its `scrollsToTop` property is YES, its delegate does not return NO from `shouldScrollViewScrollToTop`, and it is not already at the top.

// On iPhone, we execute this gesture only if there's one on-screen scroll view with `scrollsToTop` == YES. If more than one is found, none will be scrolled.

@property(nonatomicBOOL  scrollsToTop;          // default is YES.

 

4、JSON Kit數據轉換問題

json是很常用的網絡數據包格式,客戶端和服務端之間經常使用json來傳輸數據。對於一些字典類型的數據,如果某項數據為空,則會傳'<null>',使用JsonKit轉換以后會生出相應的[NSNull null]對象,而這種對象對於iOS來說並不是十分安全的,例如約定好商品的某一項字段為string類型,結果JSON Kit轉換為[NSNull null],這個時候如果不加判斷就當做是NSString處理就會存在問題。所以對於這種數據類型直接轉換為nil會更加安全,轉換方法如下:

#define PASS_NULL_TO_NIL(instance) (([instance isKindOfClass:[NSNull class]]) ? nil : instance)

針對nil調用任何方法基本上都是安全的。

 

 5、iOS 7中系統自定義VC右滑返回特性不生效

iOS 7開始系統新增了UINavigationController中VC層級右滑返回上一級的特性,該特性默認是打開的。但是在項目中有一個自定義VC中該特性無效,排查半天定位到問題如下:

self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"navigation_bar_back.png"]
                                                                        style:UIBarButtonItemStylePlain
                                                                        target:self
                                                                        action:@selector(backAction:)];

初一看這段代碼沒有任何問題,只是簡單的自定義返回按鈕。但是問題就處在這里,只要自定義了leftItem右滑返回上一層級就會實效。

因為我這個VC中UI比較復雜,ScrollView,tableView各種嵌套,因此一開始還懷疑是不是手勢沖突導致的,后來發現右滑返回屬性壓根就和我們能接觸的手勢無關。將上述代碼修改為如下代碼,問題就解決了。

if (IS_IOS_6) {
        self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"navigation_bar_back.png"]
                                                                                 style:UIBarButtonItemStylePlain
                                                                                target:self
                                                                                action:@selector(backAction:)];
}

只針對iOS 7之前的系統自定義返回按鈕,iOS 7及以后直接使用系統的返回圖標“<”。

我們也可以直接獲取這個手勢“interactivePopGestureRecognizer”,做一些定制操作。

更詳細的信息可以參考:http://www.cnblogs.com/lexingyu/p/3432444.html

 

6、UITableViewCell選中保持問題

UITableView中cell的選中態在調用ReloadData以后無法保持,為了做到選中態一直有效,我試着在cellForRowAtIndexPath中恢復選中態,代碼如下:

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellIdentifier = @"myAccountMenuCellIdentifier";
    UITableView *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
                                      reuseIdentifier:cellIdentifier];
    }
    
   ...
    
    // 恢復選中態
    if (_currentSelectedIndexPath
        && indexPath.row == _currentSelectedIndexPath.row
        && indexPath.section == _currentSelectedIndexPath.section) {
        [cell setSelected:YES animated:NO];
    }
    else {
        [cell setSelected:NO animated:NO];
    }

    return cell;
}

  發現根本不起作用,還嘗試着重載了自定義cell的

- (void)setSelected:(BOOL)selected animated:(BOOL)animated;
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated;

  也是毫無進展,最后終於通過重載reloadData,代碼如下:

- (void)reInvokeCurrentMenuItem
{
    [self selectRowAtIndexPath:_currentSelectedIndexPath
                      animated:NO
                scrollPosition:UITableViewScrollPositionNone];
    
    [self tableView:self didSelectRowAtIndexPath:_currentSelectedIndexPath];
}

  即在每次reload以后都通做一次selectRowAtIndexPath的操作來恢復選中。問題雖然解決了但是這種方法也有潛在風險,比如reload的過程中數據源發生變化,可能之前選中的cell的indexPath已經改變,輕則選中不正確的cell,嚴重的話如果刷新以后cell個數減少,傳入一個過大的indexPath就會造成崩潰。

  so此方法,請君“且用且珍惜”。

 

7、UITextField當實現了textFieldDidBeginEditing方法以后, Clearbtn不響應,原因是最簡單的view覆蓋導致事件被攔截了

  如果必須實現delegate,則可以使用設置rightView的方式

  這個問題我最后解決了,說來都不好意思,被別的View蓋住了,so出了問題還是得先思考一下是不是自己的問題。

  查這個問題得過程中,我找到一個很好用的GDB調試方法,直接在GDB中輸入以下命令即可打印當前App的view層級。

po [[UIWindow keyWindow] recursiveDescription] 

  我知道網上有個收費的工具叫Reveal,可以更炫的查看view層級,好消息是xCode6 Debug自帶了可查看view層級的功能。底層的實現機制也是一樣,個人偏執的覺得還是命令行打印的更清晰,特別是view層級很多的時候。

 

8、Block為空是調用會Crush

  昨天碰到一個crash問題,查了一下發現是Block是nil,然后我調用了該Block,程序crash。開始懷疑是不是我的block是在dispatch_async導致的crash,后面測試發現,只要block為nil,調用這個block都會crash。

  簡單示例如下:

// 定義一個block類型
typedef void (^CompleteBlock) ();
    
// 聲明一個CompleteBlock類型的變量
CompleteBlock cblock = nil;

cblock();       // 調用會crash
dispatch_async(dispatch_get_main_queue(), ^{
    cblock();   // 調用也會crash
});

  定義一個nil的block,無論怎么調用都會crash,不知道蘋果為什么沒有做保護,總之以后調用block之前還是先判斷一下比較靠譜。

 

9、UIImagePickerController黑屏問題

  使用UIImagePickerController完成拍照選取時,發現在iOS8上黑屏,其他設備都正常。查了半天才發現原來測試在系統設置中把App的Camera權限關閉了,測試也沒有注意到這點。我們一直以為這是iOS 8beta版本的bug,找了半天才發現原來原因很簡單。話說回來既然iOS7之后用戶可以控制Camera的權限,那么我們的App能不能做的更好,更友好呢,於是查了一下資料發現AVFoundation庫提供了檢測Camera授權狀態的API,所以就有了下面這個函數。

+ (void)takePhotoFromViewController:(UIViewController<UIImagePickerControllerDelegate, UINavigationControllerDelegate>*)controller
{
    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
        
        if ([[AVCaptureDevice class] respondsToSelector:@selector(authorizationStatusForMediaType:)]) {
            AVAuthorizationStatus authorizationStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
            if (authorizationStatus == AVAuthorizationStatusRestricted
                || authorizationStatus == AVAuthorizationStatusDenied) {
                
                // 沒有權限
                UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil
                                                                     message:@"Please enabled Camera Access (in Settings > Privacy > Camera)!"
                                                                    delegate:nil
                                                           cancelButtonTitle:@"OK"
                                                           otherButtonTitles:nil];
                [alertView show];
                return;
            }
        }
        
        UIImagePickerController *pickerController = [[UIImagePickerController alloc] init];
        pickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
        pickerController.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto;
        pickerController.cameraFlashMode = UIImagePickerControllerCameraFlashModeAuto;
        pickerController.cameraDevice = UIImagePickerControllerCameraDeviceRear;
        pickerController.delegate = controller;
        
        [controller presentViewController:pickerController animated:YES completion:nil];
    }
    else {
        // throw exception
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Warning"
                                                        message:@"The Device not support Camera"
                                                       delegate:nil
                                              cancelButtonTitle:@"OK"
                                              otherButtonTitles:nil];
        [alert show];
    }
}
takePhoto

  代碼中顯示檢測系統是否支持拍照,然后在檢測App是否有拍照的權限,最后才是進入拍照界面,防止模擬器調試拍照時Crash,或者真機調試權限關閉時出現的拍照界面一直黑屏的情況。

 

10、xCode Archive出來的包在本地Organizer中看到的App沒有圖標的問題

  xcassets的出現大大方便了我們提供App中對應的icon等,使我們再也不用操心icon的各種繁瑣命名了,諸如Icon-57.png等。之前也碰到過因為未提供完整的icon導致App被拒的問題,現在這些問題基本上不存在。

  昨天在Archive包以后看到本地Organizer中顯示的iPad居然沒有圖標,再三檢查xcassets,發現所有icon都有,不應該有問題啊。后來查找資料發現這可能是xCode的一個bug,本地顯示沒有圖標,但是裝到設備上一級提交到AppStore再下載下來都是有圖標的,不影響審核和使用,純粹是顯示問題。

  如何解決這個問題,檢查App中得xxx-info.plist文件中,添加Icon file屬性,並填上非retian和Retian屏幕對應的icon文件名稱(文件必須存在,且命名如下),如下圖所示:

  再次Archive即可發現,本地的Organizerz中的App有icon了。

 

 

注:記錄iOS開發中遇到的奇葩的問題,隨時更新。

  如果覺得本文幫到了你,請推薦給身邊的朋友

  轉載請著名出處,有什么問題歡迎留言

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM