IOS開發中遇到的問題及解決方法 – iPhone手機開發 iPhone軟體開發教學課程

1.報錯Switch is in protect scope

解決方法:

    switch (sender.tag) {        
     case 1:
//block方式添加動畫,這裡需要加上大括號解決報錯:Switch is in protect scope
        {
            center.y -= 20;
            [UIView animateWithDuration:1 animations:^{
                self.buttonImage.center = center;
            }];
        }
            break;
	}

2.使用UITextView輸入框上半部仍為空白

解決方法:

self.automaticallyAdjustsScrollViewInsets = NO;

凡是繼承UIScrolView的空間都會收到 automaticallyAdjustsScrollViewInsets 屬性的影響。默認為 YES ,當有UINavigationbar的時候UITextView的表現為上面空白。

3.在一個UIViewController中更改UITabBar的屬性

解決方法:
在tabBar中聲明一個更改的方法。在UIViewController中

_tabBarC = (TabBarController *)self.tabBarController;

取得tabBarController對象,再用_tabBarC去修改屬性。

4.在Navigation上自定義瞭右邊按鈕,如何取得該按鈕對象。以及該按鈕的屬性設定。

解決方法:
取得對象可以把該按鈕設為全局變量或者通過如下代碼獲取

[self.navigationController.navigationBar viewWithTag:tag];

對按鈕的外形就行設定時,放在如下代碼的前面。

self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:_sendButton];

但是對是否為禁用狀態的設定必須在其後。

5.在三級控制器中由UITabBarController控制的UINavigationCotroller中,不能通過

[self.navigationController popToViewController:mainC animated:YES];

pop到另一個UINavigationCotroller。隻能在同一UINavigationCotroller中push到不同的ViewController。

6.計算UITextView中的行數。

解決方法:

UITextView *textView = (UITextView *)[self.view viewWithTag:tag];
NSString *str = textView.text;
CGSize size = [str sizeWithAttributes:@{NSFontAttributeName:textView.font}];
int colomNumber = textView.contentSize.height/size.height;
NSLog(@"%d",colomNumber);

7.更改UISearchBar的cancel按鈕顯示文本。

解決方法:
通過遍歷定義在searchBar上的子視圖來修改。
修改之前一定要打開取消按鈕才能遍歷修改。

searchBar.showsCancelButton = YES;
for (id searchBtn in [searchBar.subviews[0] subviews]) {
    if ([searchBtn isKindOfClass:[UIButton class]]) {
        UIButton *cancalBtn = (UIButton *)searchBtn;
        cancalBtn.enabled = YES;
        [cancalBtn setTitle:@"取消" forState:UIControlStateNormal];
        break;
    }
}

8.當同一.m文件中出現兩個繼承於 UIScrollView 的類並設置瞭代理,使用

– (void)scrollViewDidScroll:(UIScrollView *)scrollView 時兩個視圖各自滾動時都會掉用該方法。可能會產生不必要的bug。
解決方法:
可以設定對應瞭tag值來限制實現對應邏輯。

9. UITableViewStylePlain UITableViewStyleGrouped 的區別

解決方法:
UITableViewStylePlain隻有一組,列表形式
UITableViewStyleGrouped可以多組,列表分組形式,

擴展:如果要在UITableViewCell的頭視圖上放視圖,看需求是怎麼樣,如果需要頭視圖跟隨tableView滾動,最好選用UITableViewStyleGrouped。
UITableViewStylePlain設置頭視圖是之後,頭視圖不會跟隨tableView滾動。當然,強行設置UITableViewStylePlain也行,不過需要在 – (void)scrollViewDidScroll:(UIScrollView *)scrollView 中進行計算處理scrollView.contentInset

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    CGFloat sectionHeaderHeight = 44;
    if (scrollView.contentOffset.y <= sectionHeaderHeight && scrollView.contentOffset.y >= 0) {
        scrollView.contentInset = UIEdgeInsetsMake(-scrollView.contentOffset.y, 0, 0, 0);
    } else if (scrollView.contentOffset.y >= sectionHeaderHeight) {
        scrollView.contentInset = UIEdgeInsetsMake(-sectionHeaderHeight, 0, 0, 0);
    }
}

10.隱藏返回按鈕

解決方法:

[self.navigationItem setHidesBackButton:YES animated:NO];

要寫在當前ViewController中。

11.取消導航欄返回按鈕的title

解決方法:

[[UIBarButtonItem appearance] setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -60) forBarMetrics:UIBarMetricsDefault];

12.PCH文件的建立

解決方法:
在Building setting中搜索Prefix Header,將它改為:$(SRCROOT)/項目名/…具體路徑/pch文件名
如:$(SRCROOT)/TestDemo/test.pch

13.自定義UIScrollView的開啟PageEnable的翻頁效果。

解決方法:

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {

//    NSLog(@"%f",targetContentOffset -> x);
//    NSLog(@"%f",velocity.x);
    static int currentIndex;
    int index = ((kScreenWidth - kCellWidthNeedCut)/2 + targetContentOffset -> x ) / (kScreenWidth - kCellWidthNeedCut);
    if (currentIndex == index) {

        if (velocity.x > 0.4 && index < _topCollectViewArray.count - 1) {
            index ++;
        } else if (velocity.x < -0.4 && index > 0){
            index --;
        }
    }
    targetContentOffset -> x =  index * (kScreenWidth - kCellWidthNeedCut);
    currentIndex = index;
}

14.JSON文件的讀取

解決方法:

//需帶上後綴名
+ (id)jsonSerializationWithName:(NSString *)jsonName {

    NSString *jsonPath = [[NSBundle mainBundle] pathForResource:jsonName ofType:nil];
    NSData *jsonData = [NSData dataWithContentsOfFile:jsonPath];
    id Dataserialization = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil];
    return Dataserialization;
}

15.iOS7 tableviewcell上面有button,但是button的點擊效果沒有

解決方法:
iOS6的UITableViewCell子視圖(subviews)的容器是UITableViewCellContentView
iOS7的UITableViewCell子視圖(subviews)的容器是UITableViewCellScrollView
由於IOS7中添加瞭滑動後出現編輯按鈕的操作,所以使用scrollView來處理,UITableViewCellScrollView有對觸摸的相應處理,導致按鈕的點擊效果被屏蔽瞭,但是點擊事件還是在的,所以可以通過

1.設置

tableView.delaysContentTouches = NO;

2.同時在 (UITableViewCell )tableView:(UITableView )tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath 代理方法中對scrollView把延遲觸摸設置為NO即可

for (id obj in cell.subviews){
        if ([NSStringFromClass([obj class])isEqualToString:@"UITableViewCellScrollView"]){
            UIScrollView *scroll = (UIScrollView *) obj;
            scroll.delaysContentTouches =NO;
            break;
        }
}

16.UITableViewCell中的使用cell和cell.contentView的區別

解決方法:
一般我們向cell中添加子視圖,有兩種方式
1.

[cell addSubview:]

2.

[cell.contentView addSubview:]

區別在於進行cell編輯時,比如cell內容向左移或者右移時,第一種方式子視圖不會移動,第二種可以,所以這種情況一般使用第二種方式。
還有在設置backgroundColor時,使用cell設置時左移或者右移顏色是不會變的,而用cell.contentCell設置時,移動後的空白會顯示cell的默認顏色,這種情況視實際情況選擇。
其實這兩種方式在大多數情況是一樣,不用糾結。

17.設置button的title屬性

解決方法:

btn.frame = CGRectMake(x, y, width, height);
[btn setTitle: @"search" forState: UIControlStateNormal];
//設置按鈕上的自體的大小
//[btn setFont: [UIFont systemFontSize: 14.0]];    //這種可以用來設置字體的大小,但是可能會在將來的SDK版本中去除改方法
//應該使用
btn.titleLabel.font = [UIFont systemFontOfSize: 14.0];
[btn seBackgroundColor: [UIColor blueColor]];
//最後將按鈕加入到指定視圖superView
[superView addSubview: btn];

```objc
btn = [[UIButton alloc] initWithFrame:CGRectMake(5,5,200,40)];
// 這樣初始化的button,文字默認顏色是白色的,所有如果背景也是白色的話,是看不到文字的,
btn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft ;//設置文字位置,現設為居左,默認的是居中
[btn setTitle:@“title” forState:UIControlStateNormal];// 添加文字
// 有些時候我們想讓UIButton的title居左對齊,我們設置
btn.textLabel.textAlignment = UITextAlignmentLeft
// 是沒有作用的,我們需要設置
btn.contentHorizontalAlignment = UIControlContentHorizonAlignmentLeft;
// 但是問題又出來,此時文字會緊貼到做邊框,我們可以設置
btn.contentEdgeInsets = UIEdgeInsetsMake(0,10, 0, 0);
// 使文字距離做邊框保持10個像素的距離。

18.項目中需要註意的地方:

解決方法:
項目更新的時候(Documents 和 Library 會被保留)
沙盒路徑中三個文件(蘋果官方推薦)
1.Documents:用戶產生的數據,都是一些比較重要的數據,比較小。這裡面的數據會自動同步到Ituns(文件
不能太大,如果太大,可能上架時會被拒絕);
2.Library:1:電影,音樂,圖片,報刊,電子書等等等 <2>Preferences文件夾(會被同步),配置文件。
3.tmp:每次應用重啟動都會自動清空
4.app:(應用程序包) 系統隱藏的。

19.取消ScrollView的反彈效果

解決方法:
self.scrollView.bounces = NO;

20.UIView的坐標轉換

解決方法:

// 將像素point由point所在視圖轉換到目標視圖view中,返回在目標視圖view中的像素值
- (CGPoint)convertPoint:(CGPoint)point toView:(UIView *)view;
// 將像素point從view中轉換到當前視圖中,返回在當前視圖中的像素值
- (CGPoint)convertPoint:(CGPoint)point fromView:(UIView *)view;
// 將rect由rect所在視圖轉換到目標視圖view中,返回在目標視圖view中的rect
- (CGRect)convertRect:(CGRect)rect toView:(UIView *)view;
// 將rect從view中轉換到當前視圖中,返回在當前視圖中的rect
- (CGRect)convertRect:(CGRect)rect fromView:(UIView *)view;
例把UITableViewCell中的subview(btn)的frame轉換到 controllerA中
// controllerA 中有一個UITableView, UITableView裡有多行UITableVieCell,cell上放有一個button
// 在controllerA中實現:
CGRect rc = [cell convertRect:cell.btn.frame toView:self.view];
// 或
CGRect rc = [self.view convertRect:cell.btn.frame fromView:cell];
// 此rc為btn在controllerA中的rect
// 或當已知btn時:
CGRect rc = [btn.superview convertRect:btn.frame toView:self.view];
// 或
CGRect rc = [self.view convertRect:btn.frame fromView:btn.superview];

21.取得當前的點和之前的點,轉換坐標系,判斷當前點是否在視圖內

解決方法:

CGPoint currentPoint = [touch locationInView:self];
CGPoint previousPoint = [touch previousLocationInView:self];
currentPoint = [self convertPoint:currentPoint toView:_myView];
_isInside = [_myView pointInside:currentPoint withEvent:event];

22.處理鍵盤彈出時,輸入框被遮擋的問題:

解決方法:當鍵盤彈起時,系統會經過註冊的觀察者發出一個通知。
1.註冊通知:

NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(keyBoardWillChangeAction:) name:UIKeyboardWillChangeFrameNotification object:nil];

2.接受通知後調用方法:

- (void)keyBoardWillChangeAction:(NSNotification *)notiInfo {

//    NSLog(@"%@“,notiInfo.name);
//    NSLog(@"%@",notiInfo.userInfo);
//    NSLog(@"%@",notiInfo.object);
    CGRect endUserInfoKey = [notiInfo.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    CGFloat endUsrY = endUserInfoKey.origin.y;
    CGFloat finalEndUser = endUsrY - self.view.frame.size.height;
    self.view.transform = CGAffineTransformMakeTranslation(0, finalEndUser);
}

23.高效設置圓角

解決方法:
如果需要將UIView的4個角全部都為圓角,做法相當簡單,隻需設置其Layer的cornerRadius屬性即可(項目需要使用QuartzCore框架)。而若要指定某幾個角(小於4)為圓角而別的不變時,這種方法就不好用瞭。並且會造成離屏渲染,參考關於性能的一些問題

對於這種情況,Stackoverflow上提供瞭幾種解決方案。其中最簡單優雅的方案,就是使用UIBezierPath。下面給出一段示例代碼。

UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(120, 10, 80, 80)];
view2.backgroundColor = [UIColor redColor]; [self.view addSubview:view2];
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:view2.bounds byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight cornerRadii:CGSizeMake(10, 10)];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = view2.bounds;
maskLayer.path = maskPath.CGPath;
view2.layer.mask = maskLayer;

其中,
byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight
指定瞭需要成為圓角的角。該參數是UIRectCorner類型的,可選的值有:

UIRectCornerTopLeftUIRectCornerTopRightUIRectCornerBottomLeftUIRectCornerBottomRightUIRectCornerAllCorners

從名字很容易看出來代表的意思,使用“|”來組合就好瞭。

24.DrawRect的註意事項:

解決方法:
-(void)drawRect:(CGRect)rect 中rect是bounds,繪制文字等操作時,用的是傳進來的rect(bounds)而不是自己設定的帶x,y坐標的rect
不能自己調用drawRect方法,而是用 [self setNeedsDisplay]; 讓系統去調用。

25.多線程中更改刷新界面在主線程還是子線程?

解決方法:
主線程。在子線程中能更新的UI界面隻是一個假象,實際上是子線程運行完畢,回到主線程繼續執行UI更新的函數棧,由於時間很短,導致這個錯覺。若子線程一直在執行,則主線程執行不瞭UI更新棧中的內容,UI界面也就不會更新。

26.Cell高度自適應:

解決方法:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

// _indexPathCell為點擊需要刷新的indexPath
    if (_indexPathCell.row == indexPath.row && _indexPathCell) {
        AYCommetModel *model = _mutableArrayOfCommentModel[indexPath.row];
        NSString *str = model.content;
        // 110為約束總長
        float textLabelWidth = kScreenWidth - 110;
        CGSize strSize = [str boundingRectWithSize:CGSizeMake(textLabelWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:15.0]} context:nil].size;
        //增益 Cell高度減去一行文字的高度
        float offSet = 70 - 17.895;
        //計算總高度
        float sumOfHeight = strSize.height  + offSet ;
//    NSLog(@"indePath.row = %ld , Size = %@,_sumOfHeight = %f",indexPath.row,NSStringFromCGSize(strSize),sumOfHeight);
        return sumOfHeight;
    }
    return 70;
}

這種方法其實並不是最好的,具體可以參考博主的這篇博客使用Masonry對cell佈局

27.NSString轉NSDictionary

解決方法:

NSData *infoData = [mutableString dataUsingEncoding:NSUTF8StringEncoding];
        NSDictionary *infoDic = [NSJSONSerialization JSONObjectWithData:infoData options:NSJSONReadingMutableContainers error:nil];

轉其他也類似,先轉成NSData再轉成其他的類。

28.從服務器GET回來的數據NSData有時候中文亂碼。

解決方法:
先看清GET回來的包頭,看清編碼方式,有些為GBK編碼的需要進行轉換。

NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
NSMutableString *mutableString = [[NSMutableString alloc] initWithData:data encoding:enc];

29.想要獲取由服務器發回來的http頭

解決方法:
需要將NSURLResponse強轉成NSHTTPURLResponse,比如status code 就調用 [httpUTLResponse statusCode]來獲取。

30.UIButton設置Selected的問題:

解決方法:
當我們想創建一個自定義背景的按鈕時,

UIButton* btn = [UIButton buttonWithType:UIButtonTypeCustom];
[btn setBackgroundImage:(UIImage*) forState:UIControlStateNormal];

如果我們想要一個selected的按鈕,

[btn setBackgroundImage:(UIImage*) forState:UIControlStateSelected];

但這樣還是有個問題,當我們設置瞭btn.selected = YES後,再去點擊按鈕,
發現會變灰色,說明在這個狀態下沒設置我們的皮膚,

[btn setBackgroundImage:(UIImage*) forState:UIControlStateSelected | UIControlStateHighlighted];

31.BOOL和bool的區別

解決方法:
說明:Objective-C 中的BOOL實際上是一種對帶符號的字符類型(signed char)的類型定義(typedef),它使用8位的存儲空間。通過#define指令把YES定義為1,NO定義為0。

註意:Objective-C 並不會將BOOL作為僅能保存YES或NO值的真正佈爾類型來處理。編譯器仍將BOOL認作8位二進制數,YES 和 NO 值隻是在習慣上的一種理解。
問題:如果不小心將一個大於1字節的整型值(比如short或int)賦給一個BOOL變量,那麼隻有低位字節會用作BOOL值。如果該低位字節剛好為0(比如8960,寫成十六進制為0x2300),BOOL值將會被認作是0,即NO值。而對於bool類型,隻有true和false的區別,即0為false,非0為true。
舉例:
BOOL b1=8960; // 實際是 NO,因為8960換成十六進制為0x2300,BOOL 隻有8位存儲空間,取0x2300的低8位,00,所以是NO
bool b2=8960; //實際是true,因為bool類型,非0即為true。

32.iOS上 更改 狀態欄(UIStatusBar)的顏色

解決方法:

1.plist設置statusBar

在plist裡增加一行 UIStatusBarStyle(或者是“Status bar style”也可以),這裡可以設置兩個值,就是UIStatusBarStyleDefault 和 UIStatusBarStyleLightContent
這樣在app啟動的launch頁顯示的時候,statusBar的樣式就是上面plist設置的風格。

2.程序代碼裡設置statusBar

[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];

或者

//相對於上面的接口,這個接口可以動畫的改變statusBar的前景色 
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent animated:YES];

不僅如此,iOS還很貼心的在UIViewController也增加瞭幾個接口,
目的是讓狀態欄根據當前顯示的UIViewController來定制statusBar的前景部分。

- (UIStatusBarStyle)preferredStatusBarStyle;

- (UIViewController *)childViewControllerForStatusBarStyle;

- (void)setNeedsStatusBarAppearanceUpdate

- (UIStatusBarStyle)preferredStatusBarStyle:

在你自己的UIViewController裡重寫此方法,返回你需要的值(UIStatusBarStyleDefault 或者 UIStatusBarStyleLightContent);

註意:

這裡如果你隻是簡單的return一個固定的值,那麼該UIViewController顯示的時候,程序就會馬上調用該方法,來改變statusBar的前景部分;如果在該UIViewController已經在顯示在當前,你可能還要在當前頁面不時的更改statusBar的前景色,那麼,你首先需要調用下面的setNeedsStatusBarAppearanceUpdate方法(這個方法會通知系統去調用當前UIViewController的preferredStatusBarStyle方法), 這個和UIView的setNeedsDisplay原理差不多(調用UIView對象的setNeedsDisplay方法後,系統會在下次頁面刷新時,調用重繪該view,系統最快能1秒刷新60次頁面,具體要看程序設置)。

- (UIViewController *)childViewControllerForStatusBarStyle:

這個接口也很重要,默認返回值為nil。
當我們調用setNeedsStatusBarAppearanceUpdate時,系統會調用application.window的rootViewController的preferredStatusBarStyle方法,我們的程序裡一般都是用UINavigationController做root,如果是這種情況,那我們自己的UIViewController裡的preferredStatusBarStyle根本不會被調用;
這種情況下childViewControllerForStatusBarStyle就派上用場瞭,
我們要子類化一個UINavigationController,在這個子類裡面重寫childViewControllerForStatusBarStyle方法,如下:

- (UIViewController *)childViewControllerForStatusBarStyle{
  return self.topViewController;
}

上面代碼的意思就是說,不要調用我自己(就是UINavigationController)的preferredStatusBarStyle方法,而是去調用navigationController.topViewController的preferredStatusBarStyle方法,這樣寫的話,就能保證當前顯示的UIViewController的preferredStatusBarStyle方法能影響statusBar的前景部分。

另外,有時我們的當前顯示的UIViewController可能有多個childViewController,重寫當前UIViewController的childViewControllerForStatusBarStyle方法,讓childViewController的preferredStatusBarStyle生效(當前UIViewController的preferredStatusBarStyle就不會被調用瞭)。

簡單來說,隻要UIViewController重寫的的childViewControllerForStatusBarStyle方法返回值不是nil,那麼,UIViewController的preferredStatusBarStyle方法就不會被系統調用,系統會調用childViewControllerForStatusBarStyle方法返回的UIViewController的preferredStatusBarStyle方法。

- (void)setNeedsStatusBarAppearanceUpdate:

讓系統去調用application.window的rootViewController的preferredStatusBarStyle方法,如果rootViewController的childViewControllerForStatusBarStyle返回值不為nil,則參考上面的講解。
設置statusBar的【背景部分】
背景部分,簡單來說,就是背景色;改變方法有兩種:
系統提供的方法
navigationBar的setBarTintColor接口,用此接口可改變statusBar的背景色

註意:一旦你設置瞭navigationBar的- (void)setBackgroundImage:(UIImage *)backgroundImage forBarMetrics:(UIBarMetrics)barMetrics接口,那麼上面的setBarTintColor接口就不能改變statusBar的背景色,statusBar的背景色就會變成純黑色。

另辟蹊徑

創建一個UIView,
設置該UIView的frame.size 和statusBar大小一樣,
設置該UIView的frame.origin 為{0,-20},
設置該UIView的背景色為你希望的statusBar的顏色,
在navigationBar上addSubView該UIView即可。

33.Xcode7HTTP協議改為瞭HTTPS協議,導致應用不正常

解決方法:
在iOS9 beta1中,蘋果將原http協議改成瞭https協議,使用 TLS1.2 SSL加密請求數據。
在info.plist中添加

NSAppTransportSecurity

	NSAllowsArbitraryLoads
		

34.如何讓TableView滾動到頂端:

解決方法:

//兩種滾動到頂部的方法都可以
//    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
//    [_centerTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
    [_centerTableView setContentOffset:(CGPoint){0,0} animated:YES];

35.在UINavigationController中設置問題

解決方法:
隻能在其中設置它的背景圖。button和title在它對應的viewController中設置

發佈留言