【IOS開發(fā)進(jìn)階系列】IOS常用開發(fā)技巧專題

1???? 工程配置類

1.1???? 添加預(yù)編譯文件

??? 將AFNetworking添加到預(yù)編譯頭文件,意味著這個框架會被自動的添加到工程的所有源代碼文件中。


1.2???? 給SDK頭文件加權(quán)限

????如果您是從DMG安裝Xcode的,看看這個技術(shù)通過Joar Wingfors,以避免通過保留所有權(quán),權(quán)限和硬鏈接意外修改SDK頭:

$ sudo ditto /Volumes/Xcode/Xcode.app /Applications/Xcode.app


2???? 調(diào)試技巧

2.1???? 日志打印類

2.1.1 讓Xcode的控制臺支持LLDB類型的打印

????這有什么用?怎么說尼,筆者認(rèn)為這個還是比較有用滴,為什么有用尼?

????因為在Xcode斷點調(diào)試的時候, 在控制臺輸入 po self.view.frame 或者 po id 類型的時候就死翹翹了。

????不信? 看如下圖 :

進(jìn)入正題

打開終端輸入三條命令:

1. touch ~/.lldbinit

2. echo display @import UIKit >> ~/.lldbinit

3. echo target stop-hook add -o “target stop-hook disable” >> ~/.lldbinit

????輸完命令后沒有任何提示? 好吧, 那恭喜你成功了~! 然后, 最關(guān)鍵的一步來了, 那就是…

????重新運(yùn)行項目(不用重啟Xcode也可以),看如下圖~~

就代表成功啦

那么現(xiàn)在我們繼續(xù)在控制臺輸入po self.view.frame

成功了!如果po指令是一個id類型也可以正常打印。是不是感覺方便很多呀? 反正我是這么覺得。至于有沒有用就看個人需要咯~~!

如何刪除?

好吧, 那么問題來了, 我用命令創(chuàng)建, 如果不想玩了怎么辦尼??

其實很簡答, 看第一條命令 touch ~/.lldbinit, 就是在根目錄下創(chuàng)建了一個隱藏文件 .lldbinit ,然后刪除這個文件就搞定啦。

打開終端然后,在終端輸入 :?

rm ~/.lldbinit 命令即可.


2.1.2 Objective-C自定義NSLog宏

/*

?XCode?LLVM?XXX?-?Preprocessing中Debug會添加?DEBUG=1?標(biāo)志

?*/

#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


2.1.3 調(diào)試宏__func__

GCC實現(xiàn)了如下的函數(shù)宏

__func__???C99的標(biāo)準(zhǔn),但是GCC只輸出函數(shù)名稱。不知道VC.NET?為啥不支持

__FUNCTION__??同__func__,

__PRETTY_FUNCTION__??非標(biāo)準(zhǔn)宏。這個宏比__FUNCTION__功能更強(qiáng),??若用g++編譯C++程序, __FUNCTION__只能輸出類的成員名,不會輸出類名;而__PRETTY_FUNCTION__則會以?<return-type>??<class-name>::<member-function-name>(<parameters-list>)?的格式輸出成員函數(shù)的詳悉信息(注:?只會輸出parameters-list的形參類型,?而不會輸出形參名).若用gcc編譯C程序,__PRETTY_FUNCTION__跟__FUNCTION__的功能相同.

而VC.NET提供的函數(shù)宏為:

__FUNCTION__?函數(shù),提供類名和函數(shù)名稱的輸出。


2.1.4 WriteLog類

添加倆個文件:WriteLog.h與WriteLog.m

WriteLog.h中:

#define ERR_LOG 1 /* 應(yīng)用程序無法正常完成操作,比如網(wǎng)絡(luò)斷開,內(nèi)存分配失敗等 */?
#define WARN_LOG 2 /* 進(jìn)入一個異常分支,但并不會引起程序錯誤 */?
#define NOTICE_LOG 3 /* 日常運(yùn)行提示信息,比如登錄、退出日志 */?
#define DEBUG_LOG 4 /* 調(diào)試信息,打印比較頻繁,打印內(nèi)容較多的日志 */

#define LOGERR(format,...) WriteLog(ERR_LOG,__FUNCTION__,__LINE__,format,##__VA_ARGS__)
#define LOGWARN(format,...) WriteLog(WARN_LOG,__FUNCTION__,__LINE__,format,##__VA_ARGS__)
#define LOGNOTICE(format,...) WriteLog(NOTICE_LOG,__FUNCTION__,__LINE__,format,##__VA_ARGS__)
#define LOGDEBUG(format,...) WriteLog(DEBUG_LOG,__FUNCTION__,__LINE__,format,##__VA_ARGS__)

void WriteLog(int ulErrorLevel, const char *func, int lineNumber, NSString *format, ...);


WriteLog.m中:

#import "WriteLog.h"

void WriteLog(int ulErrorLevel, const char *func, int lineNumber, NSString *format, ...)
{
? ? va_list args;
? ? va_start(args, format);
? ? NSString *string = [[[NSString alloc] initWithFormat:format arguments:args] autorelease];
? ? va_end(args);

? ? NSString *strFormat = [NSString stringWithFormat:@"%@%s, %@%i, %@%@",@"Function: ",func,@"Line: ",lineNumber, @"Format: ",string];

? ? NSString * strModelName = @"WriteLogTest"; //模塊名

? ? NSString *strErrorLevel = [[NSString alloc] init];
? ? switch (ulErrorLevel) {
? ? ? ? case ERR_LOG:
? ? ? ? ? ? strErrorLevel = @"Error";
? ? ? ? ? ? break;
? ? ? ? case WARN_LOG:
? ? ? ? ? ? strErrorLevel = @"Warning";
? ? ? ? ? ? break;
? ? ? ? case NOTICE_LOG:
? ? ? ? ? ? strErrorLevel = @"Notice";
? ? ? ? ? ? break;
? ? ? ? case DEBUG_LOG:
? ? ? ? ? ? strErrorLevel = @"Debug";
? ? ? ? ? ? break;
? ? ? ? default:
? ? ? ? ? ? break;
? ? }
? ? NSLog(@"ModalName: %@, ErrorLevel: %@, %@.",strModelName, strErrorLevel, strFormat);
}

控制臺測試輸出結(jié)果:

2013-03-07 16:37:17.583 WriteLog[419:207] ModalName: WriteLogTest, ErrorLevel: Notice, Function: -[ViewController pressTheButton:], Line: 66, Format: here we press the button.
2013-03-07 16:37:17.585 WriteLog[419:207] ModalName: WriteLogTest, ErrorLevel: Error, Function: -[ViewController pressTheButton:], Line: 67, Format: here we test.
2013-03-07 16:37:17.585 WriteLog[419:207] ModalName: WriteLogTest, ErrorLevel: Warning, Function: -[ViewController pressTheButton:], Line: 68, Format: second test, Yep!.


2.1.5 在控制臺里打印controller的層級

????????在控制臺里使用po [UIViewController _printHierarchy]命令即可打印出controller的層級,一目了然.大家都去玩玩吧~~1

2.1.6 在控制臺里打印view的層級

????????在控制臺里使用po [[[UIApplication sharedApplication] keyWindow] recursiveDescription]命令即可打印出view的層級,一目了然。

????????當(dāng)然,可能對于某一些人來說打印window下的所有view層級,會覺得眼花繚亂。但是,也可以打印指定某一個view的層級。

po [view recursiveDescription]

po [view recursiveDescription]

2.1.7 在debug模式下的控制臺里使用po命令打印對象的屬性和值

????????添加分類,加上代碼即可。不用導(dǎo)入頭文件,即可在控制臺里使用po命令打印出model的屬性和值

2.1.8 給category添加屬性的小技巧

????這是運(yùn)用到了對象關(guān)聯(lián), 如果不會的請看這篇文章: 時空傳送門

.h 文件

Objective-C

#import @interface NSObject (ZXPDebugDescription)


@property (copy,nonatomic) NSString *zxp_testString;


@end

#import @interface NSObject (ZXPDebugDescription)


@property (copy,nonatomic) NSString *zxp_testString;


@end

.m 文件

Objective-C

#import "NSObject+ZXPDebugDescription.h"

#import <objc runtime.h="">

@implementation NSObject (ZXPDebugDescription)

- (void)setZxp_testString:(NSString *)zxp_testString {

??? objc_setAssociatedObject(self, @selector(zxp_testString), zxp_testString, OBJC_ASSOCIATION_COPY_NONATOMIC);

}

- (NSString *)zxp_testString {

??? return objc_getAssociatedObject(self, @selector(zxp_testString));

}

@end</objc>

#import "NSObject+ZXPDebugDescription.h"

#import <objc runtime.h="">

@implementation NSObject (ZXPDebugDescription)

- (void)setZxp_testString:(NSString *)zxp_testString {

????objc_setAssociatedObject(self, @selector(zxp_testString), zxp_testString, OBJC_ASSOCIATION_COPY_NONATOMIC);

}

- (NSString *)zxp_testString {

????return objc_getAssociatedObject(self, @selector(zxp_testString));

}

@end</objc>


2.2???? 便捷開發(fā)宏定義

2.2.1 運(yùn)行時判斷運(yùn)行版本宏

Tufu

///運(yùn)行時判斷運(yùn)行版本

#define TF_IS_IPAD_RUNTIME [[[UIDevice currentDevice] model] isEqualToString:@"iPad"]

#define TF_IS_IPHONE_RUNTIME [[[UIDevice currentDevice] model] isEqualToString:@"iPhone"]

#define TF_IS_IPOD_TOUCH_RUNTIME??[[[UIDevice currentDevice] model] isEqualToString:@"iPod touch"]

#define TF_CALL_AND_MESSAGE_ABILITY_RUNTIME TF_IS_IPHONE_RUNTIME


2.2.2 ?公共庫f形式的公共前綴

///公共庫f形式的公共前綴

#undef TFC_PREFIX

#define TFC_PREFIX(a) tfc##a


2.2.3 ?摒棄函數(shù)提示

///摒棄函數(shù)提示

#if defined(__GNUC__) && (__GNUC__ >=?4) && defined(__APPLE_CC__) && (__APPLE_CC__ >=?5465)

#define TF_DEPRECATED(_version) __attribute__((deprecated))

#else

#define TF_DEPRECATED(_version)

#define TF_IS_IPAD UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad


2.2.4 ?自定義log提示

///自定義log提示

#ifdef __cplusplus

extern?"C"?{

#endif?// __cplusplus

????void?TFNetLog(NSString?*format, ...);

????void?TFLog(NSString?*format, ...);

#ifdef __cplusplus

}

#endif?// __cplusplus


2.2.5 ?release版本屏蔽log

///release版本屏蔽log

#ifdef DEBUG

#else

#define printf(...)

#define NSLog(...)

#define TFLog(...)

#define TFNetLog(...)

#endif


2.2.6 用宏定義檢測block是否可用!

Objective-C

#define BLOCK_EXEC(block, ...) if (block) { block(__VA_ARGS__); };?

// 宏定義之前的用法

/*

if (completionBlock)

{

?????completionBlock(arg1,&nbsp; arg2);

}

?*/


// 宏定義之后的用法

BLOCK_EXEC(completionBlock, arg1, arg2);

#define BLOCK_EXEC(block, ...) if (block) { block(__VA_ARGS__); };??


// 宏定義之前的用法

/*

if (completionBlock)

{

????completionBlock(arg1, arg2);

}

*/


// 宏定義之后的用法

BLOCK_EXEC(completionBlock, arg1, arg2);

3.@() 來包含C字符串 或者非OC對象

Objective-C

NSString *propertyAttributesString =

?@(property_getAttributes(class_getProperty([NSObject class], "description")));

// T@"NSString",R,C

NSString *propertyAttributesString =

?@(property_getAttributes(class_getProperty([NSObject class], "description")));

// T@"NSString",R,C


2.2.7 使用ARC和不使用ARC(from 夏夏)

Objective-C

//使用ARC和不使用ARC

#if __has_feature(objc_arc)

//compiling with ARC

#else

// compiling without ARC

#endif

//使用ARC和不使用ARC

#if __has_feature(objc_arc)

//compiling with ARC

#else

// compiling without ARC

#endif


2.2.8 讀取本地圖片(from 夏夏)

Objective-C

#define LOADIMAGE(file,ext) [UIImage imageWithContentsOfFile:[NSBundle mainBundle]pathForResource:file ofType:ext]


//定義UIImage對象

#define IMAGE(A) [UIImage imageWithContentsOfFile:[NSBundle mainBundle] pathForResource:A ofType:nil]

#define LOADIMAGE(file,ext) [UIImage imageWithContentsOfFile:[NSBundle mainBundle]pathForResource:file ofType:ext]


//定義UIImage對象

#define IMAGE(A) [UIImage imageWithContentsOfFile:[NSBundle mainBundle] pathForResource:A ofType:nil]


2.3???? 視圖調(diào)試

ios中的視圖調(diào)試(ios8蘋果引入了強(qiáng)大的新技術(shù),不可不看)

http://blog.csdn.net/openglnewbee/article/details/42195361

2.3.1 ios8以前調(diào)試控制臺命令recursiveDescription

????在ios8以前,我們想要進(jìn)行ui實時調(diào)試,可以依賴的技術(shù)手段有:

? ? ?1、用xcode啟動app,然后點擊xcode暫停運(yùn)行按鈕,然后在調(diào)試控制臺輸入下面語句:

po [[UIWindow keyWindow] recursiveDescription]

????然后就可以看到完整的UI結(jié)構(gòu)和層級關(guān)系,類似如下:

<UIWindow: 0x7b691cd0; frame = (0 0; 320 480); gestureRecognizers = <NSArray: 0x7b6921f0>; layer = <UIWindowLayer: 0x7b691e00>>

???| <UIView: 0x7c078b30; frame = (0 0; 320 480); autoresize = W+H; autoresizesSubviews = NO; layer = <CALayer: 0x7c078440>>

???|? ??| <UIView: 0x7c078ca0; frame = (10 87; 145 145); autoresize = RM+BM; autoresizesSubviews = NO; layer = <CALayer: 0x7c0786e0>>

???|? ??| <UIView: 0x7c078f20; frame = (165 87; 145 145); autoresize = RM+BM; autoresizesSubviews = NO; layer = <CALayer: 0x7c078630>>

???|? ??| <_UILayoutGuide: 0x7c079130; frame = (0 0; 0 20); hidden = YES; layer = <CALayer: 0x7c0792d0>>

? ?|? ??| <_UILayoutGuide: 0x7c079710; frame = (0 480; 0 0); hidden = YES; layer = <CALayer: 0x7c079790>>

po [self.view recursiveDescription]可以看到當(dāng)前view下的ui結(jié)構(gòu),示例如下:

<UIView: 0x7ca8ceb0; frame = (0 0; 600 600); autoresize = RM+BM; autoresizesSubviews = NO; layer = <CALayer: 0x7ca8cb30>>

???| <UIView: 0x7ca73890; frame = (10 87; 285 285); autoresize = RM+BM; autoresizesSubviews = NO; layer = <CALayer: 0x7ca89200>>

???| <UIView: 0x7ca7f520; frame = (305 87; 285 285); autoresize = RM+BM; autoresizesSubviews = NO; layer = <CALayer: 0x7ca7ce70>>

???| <_UILayoutGuide: 0x7ca8bd30; frame = (0 0; 0 0); hidden = YES; layer = <CALayer: 0x7ca814d0>>

? ?| <_UILayoutGuide: 0x7ca93b20; frame = (0 0; 0 0); hidden = YES; layer = <CALayer: 0x7ca8d530>>

2.3.2 ios8/xcode6中Debug View Hierarchy功能

????????在ios8/xcode6以后,蘋果引入了新的技術(shù)手段支持我們進(jìn)行實時ui調(diào)試;使用xcode運(yùn)行app過程中,按下底部的Debug View Hierarchy 按鈕,或者從菜單中選擇Debug > View Debugging > Capture View Hierarchy?來啟動視圖調(diào)試:

????????啟動視圖調(diào)試后,Xcode會對應(yīng)用程序的視圖層次拍一個快照并展示三維原型視圖來探究用戶界面的層級。該三維視圖除了展示app的視圖層次外,還展示每個視圖的位置、順序和視圖尺寸,以及視圖間的交互方式。

????????該調(diào)試工具非常強(qiáng)大,結(jié)合storyboard一起使用可以很好的支撐ios開發(fā)的頁面布局調(diào)整/性能優(yōu)化等需求,具體的功能這里不一一展開,請開發(fā)人員在使用中進(jìn)行總結(jié)和摸索。

2.3.3 第三方工具

2.3.3.1? Flipboard/FLEX

https://github.com/Flipboard/FLEX

Flipboard開源應(yīng)用內(nèi)調(diào)試工具FLEX

http://www.cocoachina.com/ios/20140728/9259.html


2.3.4 Xcode使用心得03:打開僵尸(Zombie)模式

????????如果打開了ARC或垃圾回收模式,在程序中發(fā)消息給以及重新分配的對象,將會引起程序崩潰。這時定位崩潰原因?qū)⒎浅@щy,因為出問題的對象已經(jīng)重新分配了。一個解決的方法就是要求Xcode將對象設(shè)置為“僵尸”,而不是重新分配。當(dāng)給僵尸對象發(fā)送消息時,會拋出一個可描述的異常,且調(diào)試器會在出錯代碼行中斷下來哦。下面看看如何打開“僵尸”模式嘍:

? ? ????依次選擇Xcode菜單: Product->Edit Scheme,進(jìn)入Diagnostics窗口,勾選Zombie Objects選項即可:

2.4???? 便捷調(diào)試類定義

2.4.1 AmIBeingDebugged(from mattt)

????????Nolan O’Brien brings the AmIBeingDebugged function to our attention from from this Technical Q&A document:

Objective-C

#include <assert.h>

#include <stdbool.h>

#include <sys types.h="">

#include <unistd.h>

#include <sys sysctl.h="">


static Bool AmIBeingDebugged(void) {

??? int mib[4];

??? struct kinfo_proc info;

??? size_t size = sizeof(info);


??? info.kp_proc.p_flag = 0;


??? mib[0] = CTL_KERN;

??? mib[1] = KERN_PROC;

??? mib[2] = KERN_PROC_PID;

??? mib[3] = getpid();


??? sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);

??? return (info.kp_proc.p_flag & P_TRACED) != 0;

}</sys></unistd.h></sys></stdbool.h></assert.h>

#include <assert.h>

#include <stdbool.h>

#include <sys types.h="">

#include <unistd.h>

#include <sys sysctl.h="">


static Bool AmIBeingDebugged(void) {

????int mib[4];

????struct kinfo_procinfo;

????size_tsize = sizeof(info);


????info.kp_proc.p_flag = 0;


????mib[0] = CTL_KERN;

????mib[1] = KERN_PROC;

????mib[2] = KERN_PROC_PID;

????mib[3] = getpid();


????sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);

????return (info.kp_proc.p_flag & P_TRACED) != 0;

}


2.4.2 檢查void *實例變量(from mattt)

????????對于逆向工程的目的,但是這是可以看的對象實例變量。它通常很容易用valueForKey這樣獲取。

????????還有一個情況下,它不能用valueForKey獲取,雖然:當(dāng)這個變量是void *類型。

Objective-C

@interface MPMoviePlayerController : NSObject <mpmediaplayback>

{

??? void *_internal;??? // 4 = 0x4

??? BOOL _readyForDisplay;? // 8 = 0x8

}</mpmediaplayback>

@interfaceMPMoviePlayerController: NSObject <mpmediaplayback>

{

????void *_internal;????// 4 = 0x4

????BOOL _readyForDisplay;??// 8 = 0x8

}</mpmediaplayback>

用底層方式來訪問

Objective-C

id internal = *((const id*)(void*)((uintptr_t)moviePlayerController + sizeof(Class)));

id internal = *((const id*)(void*)((uintptr_t)moviePlayerController + sizeof(Class)));

不要使用這段代碼,它的非常危險的。僅使用于逆向工程!


2.4.3 一個通用回調(diào)的簡單示例(from 灰灰)

.h文件

Objective-C

#import <uikit uikit.h="">


@interface UIViewController (LHYBlock)


#pragma mark - block


@property (nonatomic, copy) void (^viewControllerActionBlock)(UIViewController *vc, NSUInteger type, NSDictionary *dict);


#pragma mark - viewControllerAction


/**

?*? View 事件的block回調(diào)

?*

?*? @param viewControllerActionBlock block的參數(shù)有view本身,狀態(tài)碼,鍵值對。

?*/

- (void)viewControllerAction:(void (^)(UIViewController *vc, NSUInteger type, NSDictionary *dict))viewControllerActionBlock;


@end</uikit>

#import <uikit uikit.h="">


@interface UIViewController (LHYBlock)


#pragma mark - block


@property (nonatomic, copy) void (^viewControllerActionBlock)(UIViewController *vc, NSUInteger type, NSDictionary *dict);


#pragma mark - viewControllerAction


/**

*??View 事件的block回調(diào)

*

*??@param viewControllerActionBlock block的參數(shù)有view本身,狀態(tài)碼,鍵值對。

*/

- (void)viewControllerAction:(void (^)(UIViewController *vc, NSUInteger type, NSDictionary *dict))viewControllerActionBlock;


@end</uikit>

.m 文件

Objective-C

#import "UIViewController+LHYBlock.h"

#import <objc runtime.h="">

@implementation UIViewController (LHYBlock)

#pragma mark - runtime associate


- (void)setViewControllerActionBlock:(void (^)(UIViewController *vc, NSUInteger type, NSDictionary *dict))viewControllerActionBlock {

??? objc_setAssociatedObject(self, @selector(viewControllerActionBlock), viewControllerActionBlock, OBJC_ASSOCIATION_COPY);

}


- (void (^)(UIViewController *, NSUInteger, NSDictionary *))viewControllerActionBlock {

??? return objc_getAssociatedObject(self, @selector(viewControllerActionBlock));

}


#pragma mark - block


- (void)viewControllerAction:(void (^)(UIViewController *vc, NSUInteger type, NSDictionary *dict))viewControllerActionBlock {

??? self.viewControllerActionBlock = nil;

??? self.viewControllerActionBlock = [viewControllerActionBlock copy];

}


#pragma mark -

@end</objc>

#import "UIViewController+LHYBlock.h"

#import <objc runtime.h="">

@implementation UIViewController (LHYBlock)

#pragma mark - runtime associate


- (void)setViewControllerActionBlock:(void (^)(UIViewController *vc, NSUInteger type, NSDictionary *dict))viewControllerActionBlock {

????objc_setAssociatedObject(self, @selector(viewControllerActionBlock), viewControllerActionBlock, OBJC_ASSOCIATION_COPY);

}


- (void (^)(UIViewController *, NSUInteger, NSDictionary *))viewControllerActionBlock {

????return objc_getAssociatedObject(self, @selector(viewControllerActionBlock));

}

#pragma mark - block

- (void)viewControllerAction:(void (^)(UIViewController *vc, NSUInteger type, NSDictionary *dict))viewControllerActionBlock {

????self.viewControllerActionBlock = nil;

????self.viewControllerActionBlock = [viewControllerActionBlockcopy];

}

#pragma mark -

@end</objc>

import這個類 , 就能用block, 參數(shù)都是通用的本身,狀態(tài)碼,字典.(灰神提供)


2.4.4 自定義弱關(guān)聯(lián)對象(weak associated objects)

????不幸的是,關(guān)聯(lián)對象不支持弱引用。 幸運(yùn)的是,很容易實現(xiàn)。你只需要一個簡單的類包裝與弱引用一個對象.

Objective-C

@interface WeakObjectContainter : NSObject

????@property (nonatomic, readonly, weak) id object;

@end


@implementation WeakObjectContainter

- (instancetype)initWithObject:(id)object {

??? self = [super init];

??? if (!self) {

??????? return nil;

? ??}


??? _object = object;


??? return self;

}

@end

@interface WeakObjectContainter: NSObject

@property (nonatomic, readonly, weak) id object;

@end


@implementation WeakObjectContainter

- (instancetype)initWithObject:(id)object {

????self = [super init];

????if (!self) {

????????return nil;

????}


????_object = object;

????return self;

}

@end

設(shè)置與獲取

Objective-C

// 設(shè)置弱引用關(guān)聯(lián)

objc_setAssociatedObject(self, &MyKey, [[WeakObjectContainter alloc] initWithObject:object], OBJC_ASSOCIATION_RETAIN_NONATOMIC);


//獲取弱引用關(guān)聯(lián)

id object = [objc_getAssociatedObject(self, &MyKey) object];

// 設(shè)置弱引用關(guān)聯(lián)

objc_setAssociatedObject(self, &MyKey, [[WeakObjectContainter alloc]initWithObject:object], OBJC_ASSOCIATION_RETAIN_NONATOMIC);


//獲取弱引用關(guān)聯(lián)

id object = [objc_getAssociatedObject(self, &MyKey) object];


2.4.5 動態(tài)調(diào)用block(黑魔法)

Objective-C

//定義一個block

id (^testBlock)(NSString *string,NSArray *array) = ^id(NSString *string,NSArray *array) {

??????????? NSLog(@"param:--%@--%@",string,array);

??????????? return string;

??????? };


??????? // _Block_signature? 是iOS的私有api

??????? const char * _Block_signature(void *);

??????? const char * signature = _Block_signature((__bridge void *)(testBlock));


??????? NSMethodSignature *methodSignature = [NSMethodSignature signatureWithObjCTypes:signature];

??????? NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];

??????? [invocation setTarget:testBlock];


??????? NSString *string = @"string";

??????? [invocation setArgument:&string atIndex:1];


??????? NSArray *array = @[@"xx",@"oo"];

??????? [invocation setArgument:&array atIndex:2];


??????? [invocation invoke];


??????? id returnValue;

??????? [invocation getReturnValue:&returnValue];

??????? NSLog(@"returnValue : %@",returnValue)

3???? APP崩潰調(diào)試技巧

3.1???? APP啟動后崩潰調(diào)試

4???? 兼容性處理

4.1???? 系統(tǒng)定義宏

4.1.1 __OSX_AVAILABLE_BUT_DEPRECATED宏

????????我們在開發(fā)的過程中會發(fā)現(xiàn)某些方法被deprecated了,這是因為這些方法已經(jīng)被更好的方法代替了,或者是這些放在在當(dāng)初設(shè)計的時候考慮不全面等。

__OSX_AVAILABLE_BUT_DEPRECATED() 宏說明,在某個版本開始引進(jìn)一個方法,

????但是在某個版本之后廢棄了。

__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0,__MAC_10_5,__IPHONE_NA,__IPHONE_NA)

????在mac os x 10.0 開始引進(jìn)這個方法,但是在10.5之后廢棄了,ios上從來沒只支持過。


????我們可以自己寫一些方法

extern void mymacfunc() __OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_NA);

????這個函數(shù)在mac os x 10.5之后可用,在ios上不可用

???? @interface MyClass : NSObject
??????????? -(void) mymacmethod __OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_NA);

??????????? -(void) mymacandiosmethod
????? @end

????這個類中的mymacmethod 在mac os x 10.5可用,在ios上不可用,但是mymacandiosmethod就沒有限制了。

4.1.2 ?__OSX_AVAILABLE_STARTING

有時候我們會看到這樣的東西?

CA_EXTERN NSString * const kCATransitionFromRight
????__OSX_AVAILABLE_STARTING?(__MAC_10_5, __IPHONE_2_0);

__OSX_AVAILABLE_STARTING 是什么意思呢?

????我們知道 Mac OS X and iOS有不同的版本號,__OSX_AVAILABLE_STARTING 宏允許你同時指定Mac OS X and iOS的版本號。

__OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0)它表示從 mac os x10.5 和ios 2.0 才開始使用的,兩種平臺都支持。


有時候我們只想支持一種平臺,怎么辦呢?

__????OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_NA)

????它表示 只支持mac os x? 不支持ios平臺,最后的NA 表示not? applicable ,是這兩個單詞的縮寫

4.1.3 ?__IPHONE_OS_VERSION_MIN_REQUIRED

#ifdef? __IPHONE_OS_VERSION_MIN_REQUIRED

// 只能在ios 下

??????? #if __IPHONE_OS_VERSION_MIN_REQUIRED > 40300
??????? //做一些事情
??????? #else
??????? //做一些事情

??????? #endif

#endif


4.1.4 ?__MAC_OS_X_VERSION_MIN_REQUIRED

?#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
?// 只能在mac os x
? ? ? ? ? ? ?? #if __MAC_OS_X_VERSION_MIN_REQUIRED < 1050
??????????????? // code in here might run on pre-Leopard OS

?????????????? #else
??????????????? // code here can assume Leopard or later
?????????????? #endif
?#endif

????有時候,一些功能可能需要某一個版本之上才能使用,這時候我們可以使用上面的方法。

4.1.5 ?__IPHONE_X_X

#ifndef __IPHONE_3_0
#warning "This project uses features only available in iPhone SDK 3.0 and later."

#endif

????從字面意思看,如果我們的sdk版本低于3.0可能就會報錯。不知道對不對,沒試過。一般,如果我們的sdk 版本為x,在<Availability.h> 文件中都會 #define 一下,如果我們的sdk版本為x? 就會#define __IPHONE_X_X ?? xxxxx

????所以根據(jù)這點,我們可以處理在不同版本之間某些方法的切換

?#ifdef __IPHONE_6_1
??? methodOne;
?#else
??? methodTwo;
?#endif


4.2???? 系統(tǒng)版本判斷

4.2.1 ?IOS開發(fā)中如何區(qū)分IOS版本

//?當(dāng)前系統(tǒng)支持的最小版本

__IPHONE_OS_VERSION_MIN_REQUIRED

//?當(dāng)前系統(tǒng)支持的最大版本

__IPHONE_OS_VERSION_MAX_ALLOWED


//比如用?iPhone OS SDK 3.1.2?編譯的程序

__IPHONE_OS_VERSION_MIN_REQUIRED?==?__IPHONE_3_0

__IPHONE_OS_VERSION_MAX_ALLOWED?==?__IPHONE_3_1


//這時,我們可以在程序中使用下面類似的?#ifdef?語句:

#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_2_2

? ??// iPhone OS SDK 3.0?以后版本的處理

#else

? ??// iPhone OS SDK 3.0?之前版本的處理

#endif


//又或者?iPhone OS SDK 4?推出的時候,可以:

#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_2_2

? ??#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_3_1

? ? ? ??// iPhone OS SDK 4.0?以后版本的處理

? ??#else

? ? ? ??// iPhone OS SDK 3.0 ~ 4.0?版本的處理

? ??#endif

#else

? ??// iPhone OS SDK 3.0?之前版本的處理

#endif


5???? 代碼基礎(chǔ)

5.1???? 數(shù)據(jù)類型相關(guān)

5.1.1 Objective-C中的instancetype和id區(qū)別

????instancetype的作用,就是使那些非關(guān)聯(lián)返回類型的方法返回所在類的類型!

1、相同點

????都可以作為方法的返回類型

2、不同點

①instancetype可以返回和方法所在類相同類型的對象,id只能返回未知類型的對象;

②instancetype只能作為返回值,不能像id那樣作為參數(shù)


http://blog.csdn.net/kuizhang1/article/details/18048829


5.1.2 weakSelf與strongSelf宏定義寫法

#define WS(weakSelf)? __weak __typeof(&*self)weakSelf = self

#define StrongSelf(strongSelf)? __strong __typeof(&*self) strongSelf = self


weakself的一種寫法

http://www.tuicool.com/articles/bYBB7r


6???? 性能優(yōu)化

6.1???? 圖片資源讀取優(yōu)化

6.1.1 iOS圖片內(nèi)存優(yōu)化(博文)內(nèi)存優(yōu)化經(jīng)驗(from 灰灰)

解決步驟:instrument調(diào)試后,發(fā)現(xiàn)沒被釋放的全是imageIO,差不多就知道了,把讀圖的方式,從[UIImage imageNamed:@”“],改成imageWithContentsOfFile,就可以了。

問題原因:imageNamed讀取圖片的方法,會緩存在內(nèi)存中,所以較大的圖片,還是用imageWithContentsOfFile。?

Tip1:.xcassets里的圖片無法用imageWithContentsOfFile讀?。?

Tip 2:imageWithContentsOfFile讀取圖片需要加文件后綴名如png,jpg等;?

灰神內(nèi)存優(yōu)化鏈接地址點此


7???? 參考鏈接

iOS SDK:那些關(guān)于iOS調(diào)試的技巧

http://dev.yesky.com/62/34881062.shtml

iOS自定義NSLog日志

http://www.verydemo.com/demo_c134_i22023.html

iOS編程高性能之路-自定義宏總結(jié)

http://blog.sina.com.cn/s/blog_7011f21c0101c3jc.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容