iOS開發細節(45條)

** 1. 隱藏分欄控制器的UITabBar **

當從一個視圖控制器切換到另一個視圖控制器,新的視圖控制器不需要顯示分欄條,而返回時要求顯示出來,在切換時可以將新的視圖控制器的hidesBottomBarWhenPushed 設置成YES;

** 2. 自定義NSLog的打印格式**
比如: ViewController.m : 70 ViewController.m文件第70行的NSLog打印內容

#ifdef DEBUG
#define NSLog(FORMAT, ...) fprintf(stderr,"%s  : %d  \t%s\n",[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);
#else
#define NSLog(FORMAT, ...) nil
#endif

** 3. 創建pch文件的方法**

點擊Supporting Files 選擇 New File, 選擇 IOS, Other 中的 PCH File,創建完成。
選中項目 Bulid Phases 找到Prefix Header, 在右側添加 $(SRCROOT)/pingui/PrefixHeader.pch

說明:pingui是項目名稱

在story里面如果畫了多個view controller 通過button切換的話 直接在button上托一根線到指定的view controller 選擇present modaly

** 4. CocoaPods **

1.先創建工程
2.在終端中切換到項目文件夾
3.執行 pod init 命令,會創建一個Podfile的文件夾
4.編輯該文件,執行 vim Podfile命令
5.輸入下面的內容

# Uncomment this line to define a global platform for your project
# platform :ios, ‘7.0’ // 7.0表示支持的最低版本
# Uncomment this line if you're using Swift
# use_frameworks!

// 在這里輸入要添加的三方庫名稱,版本號
// >= 表示最低版本 ~> 表示兼容版本 == 表示指定版本
// 如果不寫版本號 默認為最新版 
pod 'AFNetworking', '~>2.5.4'
pod ‘SDWebImage'

6.編輯完成后保存
7.執行 pod install命令 出現 pods installed 表示安裝成功
8.完全退出Xcode
9.啟動xcworkspace文件

pod search 三方庫名稱 可以查看該庫的所有版本

** 5. 設置應用圖標 **

使用iconkit軟件
鏈接: http://pan.baidu.com/s/1i4fvYdv 密碼: z6k7
將一張1024*1024的png格式圖片拖入iconkit 然后根據需要選擇相應的版本

選擇機型.png

根據實際情況選擇適合不同機型的圖片

點擊preview(預覽)或者直接保存,然后選擇保存路徑

保存.png

記住第一個勾勾上(它會自動創建一個AppIcon.appiconset文件夾),在項目中找到Images.xcassets點右鍵 選擇showInFinder 把之前用iconkit生成的AppIcon.appiconset文件夾替換里面的AppIcon.appiconset

** 6. 啟動頁 **

如果需要兼容ios7.0版本的 需要在images.xcassets文件中 添加 LaunchingImage
然后添加相應的圖片
點擊項目 General 在App Icons and Launch Images 中第二項 選擇launchImage

如果是7.0之后的,可以直接在LaunchScreen.xib里面 先把項目名稱那個Label刪除,然后添加imageview,把imageView的背景圖設置成啟動圖就OK了

** 7. 創建類型時選擇 NSClassFromString把字符串轉換成類對象 **

 GPShape *currentShape = [[NSClassFromString(_currentShapeType) alloc] init];

** 8. 給UILabel添加刪除線 **

NSMutableAttributedString *attri = [[NSMutableAttributedString alloc] initWithString:cell.priceLabel.text];
    [attri addAttribute:NSStrikethroughStyleAttributeName value:@(NSUnderlinePatternSolid | NSUnderlineStyleSingle) range:NSMakeRange(0, cell.priceLabel.text.length)];
    [attri addAttribute:NSStrikethroughColorAttributeName value:[UIColor redColor] range:NSMakeRange(0, cell.priceLabel.text.length)];
    [cell.priceLabel setAttributedText:attri];

** 9. block 里面使用了 self 要使用weak self **

    __weak typeof (self) weakself = self;

** 10. 圖片加載 **

UIImage的imageNamed方法加載的圖片是做了單例化的處理 圖片會一直存在于內存中 因此只適合用來處理小圖標 不適合動態加載大量圖片

cell.imageView.image = [UIImage imageNamed:@“美女"]; // 此方法會占用大量內存
    NSString *imageFilename = [[NSBundle mainBundle] pathForResource:@“美女"
 ofType:nil];
    cell.imageView.image = [UIImage imageWithContentsOfFile:imageFilename];

** 11. 單例同步保護 **

// 第一種方法
+(instancetype)sharedManager{
    static GPBookManager *sharedManager = nil;
    //第二次時不會執行這條語句,因為是static
    //同步保護(只允許一個線程進入下面的代碼塊執行 如果有多個線程 其它線程需要排隊等待之前進入的線程離開同步塊以后才能進入同步塊 這樣即便在多線程環境下也能保證該類只能創建出一個對象)
    @synchronized (self) {
        if (sharedManager == nil) {                             //if(!shardedManager)等效
            sharedManager = [[GPBookManager alloc]initPrivate];
        }
    }
    return sharedManager;
}
// 第二種方法
+(instancetype)sharedSNSContext{
    static GPSNSContext *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (!instance) {
            instance = [[self alloc] initPrivate];
        }
    });
    return instance;
}

** 12. 去掉字符串的空格 **

[str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]

** 關于給應用程序命名的方法 **

Bundle name - 簡單來說是 App 安裝到 iOS 機子里的 App 文件夾名。
Executable name – 執行程序名,默認與 PRODUCT_NAME 一致。
Bundle display name – 真正顯示到用戶屏幕上的 App 名稱。
可見在模擬器/真機上顯示的名字是由Bundle Display Name決定的。默認情況下Bundle Display Name就等同于Product Name,所以就造成了我認為Product Name就是應用顯示名的錯覺。
另外發現,在部分情況下如果Product Name為中文字符,會導致編譯運行在真機時,第一次必報 Could not inspect the application package 錯誤,這個可以參考《使用 Xcode6 在 iOS8 設備上調試報錯 Could not inspect the application package》。

** 13. 沙箱路徑 **

NSLog(@"%@",NSHomeDirectory());

** 14. 數據需要保存在沙箱中的 Documents **

** 15. 將圖片轉成成二進制數據 **

NSData *data = UIImagePNGRepresentation(UIImage *image)

** 16. 如果使用故事版繪制 **
如果直接繪制在storyboard里面 不能使用 alloc init

** 17. UITableView單元格的高度 **

-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    if (indexPath.section == 0 && indexPath.row == 5) {
        return 60;
    }
    return 110;
}

** 18. 設置組名欄的高度 **

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
    return 40;
}
// 設置兩個分組名稱之間的距離(即每組最后一個底部與下一個組名欄頂部之間的距離)
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
    return 10;
}
//每個分組的第一個表格到分組頂部的距離
- (CGFloat) tableView:(UITableView *)tableView estimatedHeightForHeaderInSection:(NSInteger)section{
    return 40;
}

** 19. 分欄控制器 **
// 創建分欄控制器若采用系統默認方式 要指定每一個視圖控制器的tabBarItem 否則其它分欄項不顯示出來

// 第一種情況 只創建一個導航控制器
缺點: 默認狀態沒選中

// 第二種情況 有多少個視圖控制器就創建多少個導航控制器
優點:默認狀態已選中

** 20. 導航 **

導航欄透明度

self.navigationController.navigationBar.translucent = YES;

** 21. 顯示導航欄的工具欄 **

self.navigationController.toolbarHidden = NO;

** 22. 如何讓創建的導航項和工具欄的項均勻分布 **

UIBarButtonItem *item1 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCamera target:self action:@selector(openAlbum:)];
// 創建導航項:
self.navigationItem.leftBarButtonItems = @[Item1, Item3,  Item2];
// 創建工具欄欄上的項:
self.toolbarItems = @[item1, item3, item2];

** 提示: _BAD_ACESS 通常表示的是野指針 **

** 23. NSBundle **

    // q文件名 plist文件類型
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"q" ofType:@“plist"];
    // 從文件中獲取數據
    NSData *data = [NSData dataWithContentsOfFile:filePath];

** 24. 模態警告框 **

    // UIAlertControllerStyleActionSheet 從下面彈出
    // UIAlertControllerStyleAlert從屏幕中間彈出
    UIAlertController *ac = [UIAlertController alertControllerWithTitle:@"警告" message:@"這是一個警告" preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *ok = [UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:nil];
    //UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:nil];
    [ac addAction:ok];
    //[ac addAction:cancel];
    [self presentViewController:ac animated:YES completion:nil];

** 25. 觸底加載更多 **

// 回調方法
-(void) scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
    if (currentPage >= 1 && scrollView == myTableView) {
        // if (scrollView == myTableView) 等效
        CGPoint offset = scrollView.contentOffset;
        if (offset.y - 50 > scrollView.contentSize.height - HEIGHT) {
            currentPage += 1;
            [self requestDataFromServer];
        }
   }
}

** 26. 隱藏分欄項 **

self.tabBarController.tabBar.hidden = YES;
@property (nonatomic,weak) id<GPAwakable> delegate; //破壞循環的環 避免造成內存泄露 只要是協議委托都用weak
    // 獲取window
    UIWindow *window = [UIApplication sharedApplication].keyWindow;
    // 當手機處于豎屏或者橫屏時獲取到的screen時不一樣的
    CGRect screen = [[UIScreen mainScreen] bounds];
    // 更改window的大小
    CGRect half = CGRectMake(0, screen.size.height / 2, screen.size.width, screen.size.height);
    [window setFrame:half];

** 27. 百分號編碼互轉**

    // iOS9之后
    NSString *str = @"今天,你還好嗎?";
    // 轉成百分號編碼
    NSString *str1 = [str stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    NSLog(@"%@",str1);
    // 將百分號編碼解碼
    NSString *str2 = [str1 stringByRemovingPercentEncoding];
    NSLog(@"%@",str2);

** 28. 鎖定系統文件**

是不是還在為誤刪了Xcode里面的系統文件而煩惱呢?下面介紹一種鎖定的方法,這樣再也不用擔心了。
1.點擊Finder,切換到應用程序,找到Xcode,右鍵,顯示包內容
2.打開終端,切換到該目錄。(cd 將Contents文件夾拖入終端中)
3.回到上一級
4.執行 `sudo chown -hR root:wheel Contents`
5.輸入電腦密碼,然后靜靜地等幾分鐘就大功告成了。
123.png

** 29. 去掉網頁代碼中的標簽**

-(NSString *)filterHTML:(NSString *)ahtml{
    NSScanner * scanner = [NSScanner scannerWithString:ahtml];
    NSString * text = nil;
    while([scanner isAtEnd]==NO){
        //找到標簽的起始位置
        [scanner scanUpToString:@"<" intoString:nil];
        //找到標簽的結束位置
        [scanner scanUpToString:@">" intoString:&text];
        //替換字符
        ahtml = [ahtml stringByReplacingOccurrencesOfString:[NSString stringWithFormat:@"%@>",text] withString:@""];
    }
    return ahtml;
}

** 30. 使用webView加載html **

[_myWebView loadHTMLString:self.htmlStr baseURL:nil];

** 31. 圖片資源異常 **
錯誤提示:

錯誤提示.png

這是Xcode里的copypng程序出錯了,png圖片本身是有問題的,出現了交錯問題。
一種辦法是在項目的Build Settings中把Compress PNG files選擇設置為NO。這種方法打包的時候文件可能很大哦

還有就是看看這個地方有沒有紅顏色的東西,如果有就是圖片資源有問題。或者你試一試把png圖片用工具重新導出一下。

** 32. 數據解析 **
我們往往需要對特殊情況進行處理,但有時候我們會出現下面的json串:

{
  "code" : 50003,
  "data" : null,
  "msg" : "沒有數據",
  "success" : true,
  "type" : "類型"
}

這種情況下我們要排除當data的值為null的情況,判斷條件應該這樣寫

if ([response[@"data"] isEqual:[NSNull null]]) {
    NSLog(@"沒有相關數據~");
}

也可以寫成

if (response[@"data"] == [NSNull null]) {
    NSLog(@"沒有相關數據~");
}

** 33. url中包含有空格 **
數據請求時,參數中需要傳遞一個帶有空格的參數,比如時間: 2016-05-23 21:05:15 日期和時間中間有個空格,如果直接把這個作為參數的話,程序會崩潰的。不信你試試~~
解決辦法:將空格用加號代替。2016-05-23+21:05:15

** 34. 非模態提示框 **
鏈接: http://pan.baidu.com/s/1hsc0Prm 密碼: chth

** 35. 時間和時間戳 **

    NSDate *datenow = [NSDate date];
    NSLog(@"系統當前時間: %@",datenow);
    NSString *timeSp = [NSString stringWithFormat:@"%ld", (long)[datenow timeIntervalSince1970]];
    NSLog(@"時間戳 秒數(1970): %@",timeSp);
    NSInteger start = [timeSp integerValue];

    // 將時間戳轉成時間
    NSDate *startDate = [NSDate dateWithTimeIntervalSince1970:start];
    // 定義時間顯示格式
    NSDateFormatter *formater = [[NSDateFormatter alloc] init];
    [formater setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSString *startTime = [formater stringFromDate:startDate];
    NSLog(@"%@", startTime);

** 36. 真機測試版本號文件路徑 **

在終端執行下面的命令

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport

** 37. 收集崩潰信息 **

void UncaughtExceptionHandler(NSException *exception) {
    NSArray *arr = [exception callStackSymbols];//得到當前調用棧信息
    NSString *reason = [exception reason];//崩潰的原因
    NSString *name = [exception name];//異常類型
    NSLog(@"exception type: %@ \n crash reason : %@ \n call stack info : %@", name, reason, arr);
    // 這里可以收集崩潰日志
    
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
    
    return YES;
}

** 38. NSLog語句在Debug模式下打印,Release模式下不打印**

在-Prefix.pch文件中,加上下面一段代碼,當設置為Debug模式下,可以打印NSLog了。設置Release,發布app版本的時候就不會打印了,這樣可以提高性能。

#ifdef DEBUG
#define NSLog(...) NSLog(__VA_ARGS__)
#define debugMethod() NSLog(@"%s", __func__)
#else
#define NSLog(...)
#define debugMethod()
#endif

** 39. 判斷一個ViewController消失的時候是push還是pop **

// 判斷一個ViewController消失的時候是push還是pop
- (void)viewWillDisappear:(BOOL)animated {
    NSArray *viewControllers = self.navigationController.viewControllers;
    if (viewControllers.count > 1 && [viewControllers objectAtIndex:viewControllers.count - 2] == self) {
        // View is disappearing because a new view controller was pushed onto the stack
        NSLog(@"New view controller was pushed");
    }
    else if ([viewControllers indexOfObject:self] == NSNotFound) {
        // View is disappearing because it was popped from the stack
        NSLog(@"View controller was popped");
    } 
}

** 40. 檢測QQ、微信、微博是否安裝 **

if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"weixin://"]]){
        NSLog(@"已經安裝微信");
    }
    if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"mqq://"]]){
        NSLog(@"已經安裝QQ");
    }
    if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"sinaweibo://"]]){
        NSLog(@"已經安裝微博");
    }

** 41. 是否隱藏狀態欄 **

-(BOOL)prefersStatusBarHidden{
    return YES;
}

** 42.修改UITabBar的背景色 **

    // 修改bar背景色(方法一)
    //[UITabBar appearance].barTintColor = [UIColor redColor];
    
    // 修改bar背景色(方法二)
    //UIView *backView = [[UIView alloc] initWithFrame:self.tabBar.bounds];
    //backView.backgroundColor = [UIColor greenColor];
    //[[UITabBar appearance] insertSubview:backView atIndex:0];
    
    // 修改bar背景色(方法三 圖片)
    //[[UITabBar appearance] setBackgroundImage:[UIImage imageNamed:@"bar背景色"]];
    
    // 最后請加上下面這句話
    self.tabBar.translucent = NO;

** 43. 隱藏導航欄下邊緣線 **

@interface ViewController (){
    UIImageView *navigationImageView;
}

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.navigationController.navigationBar.barTintColor = [UIColor whiteColor];
    self.view.backgroundColor = [UIColor whiteColor];
    navigationImageView = [self findHairlineImageViewUnder:self.navigationController.navigationBar];
}

-(void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    navigationImageView.hidden = YES;
}

-(UIImageView *)findHairlineImageViewUnder:(UIView *)view {
    if ([view isKindOfClass:UIImageView.class] &&
        view.bounds.size.height <= 1.0) {
        return (UIImageView *)view;
    }
    for (UIView *subview in view.subviews) {
        UIImageView *imageView = [self findHairlineImageViewUnder:subview];
        if (imageView) {
            return imageView;
        }
    }
    return nil;
}

** 44. 驗證IP地址 **

- (BOOL)valiIP:(NSString *)IP{
    NSString *str = @"^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\.(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\.(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\.(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)$";
    NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", str];
    return [pred evaluateWithObject:IP];
}

** 45. 啟動圖 **

今天我們只討論豎屏Portrait的情況;
目前支持的iOS版本有三種選擇:

  1. iOS 8.0 and Later

  2. iOS 7.0 and Later

  3. iOS 6.0 and Prior

每個版本需要的圖片尺寸:

iOS版本 尺寸
iOS 8.0 and Later 750*1334
1242*2208
iOS 7.0 and Later 640*960
640*1136
iOS 6.0 and Prior 320*480
640*960
640*1136
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容