前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【IOS开发进阶系列】IOS常用开发技巧专题

【IOS开发进阶系列】IOS常用开发技巧专题

作者头像
江中散人_Jun
发布2023-10-16 11:36:11
4320
发布2023-10-16 11:36:11
举报
文章被收录于专栏:云原生布道专栏

1     工程配置类

1.1     添加预编译文件

    将AFNetworking添加到预编译头文件,意味着这个框架会被自动的添加到工程的所有源代码文件中。

1.2     给SDK头文件加权限

    如果您是从DMG安装Xcode的,看看这个技术通过Joar Wingfors,以避免通过保留所有权,权限和硬链接意外修改SDK头:

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

2     调试技巧

2.1     日志打印类

2.1.1 让Xcode的控制台支持LLDB类型的打印

    这有什么用?怎么说尼,笔者认为这个还是比较有用滴,为什么有用尼?

    因为在Xcode断点调试的时候, 在控制台输入 po self.view.frame 或者 po id 类型的时候就死翘翘了。

    不信? 看如下图 :

进入正题

打开终端输入三条命令:

1. touch ~/.lldbinit

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

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

    输完命令后没有任何提示? 好吧, 那恭喜你成功了~! 然后, 最关键的一步来了, 那就是…

    重新运行项目(不用重启Xcode也可以),看如下图~~

就代表成功啦

那么现在我们继续在控制台输入po self.view.frame

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

如何删除?

好吧, 那么问题来了, 我用命令创建, 如果不想玩了怎么办尼??

其实很简答, 看第一条命令 touch ~/.lldbinit, 就是在根目录下创建了一个隐藏文件 .lldbinit ,然后删除这个文件就搞定啦。

打开终端然后,在终端输入 :?

rm ~/.lldbinit 命令即可.

2.1.2 Objective-C自定义NSLog宏

/*

 XCode LLVM XXX - Preprocessing中Debug会添加 DEBUG=1 标志

 */

#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 调试宏__func__

GCC实现了如下的函数宏

__func__   C99的标准,但是GCC只输出函数名称。不知道VC.NET 为啥不支持

__FUNCTION__  同__func__,

__PRETTY_FUNCTION__  非标准宏。这个宏比__FUNCTION__功能更强,  若用g++编译C++程序, __FUNCTION__只能输出类的成员名,不会输出类名;而__PRETTY_FUNCTION__则会以 <return-type>  <class-name>::<member-function-name>(<parameters-list>) 的格式输出成员函数的详悉信息(注: 只会输出parameters-list的形参类型, 而不会输出形参名).若用gcc编译C程序,__PRETTY_FUNCTION__跟__FUNCTION__的功能相同.

而VC.NET提供的函数宏为:

__FUNCTION__ 函数,提供类名和函数名称的输出。

2.1.4 WriteLog类

添加俩个文件:WriteLog.h与WriteLog.m

WriteLog.h中:

#define ERR_LOG 1 /* 应用程序无法正常完成操作,比如网络断开,内存分配失败等 */  #define WARN_LOG 2 /* 进入一个异常分支,但并不会引起程序错误 */  #define NOTICE_LOG 3 /* 日常运行提示信息,比如登录、退出日志 */  #define DEBUG_LOG 4 /* 调试信息,打印比较频繁,打印内容较多的日志 */

#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); }

控制台测试输出结果:

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的层级,一目了然。

        当然,可能对于某一些人来说打印window下的所有view层级,会觉得眼花缭乱。但是,也可以打印指定某一个view的层级。

po [view recursiveDescription]

po [view recursiveDescription]

2.1.7 在debug模式下的控制台里使用po命令打印对象的属性和值

        添加分类,加上代码即可。不用导入头文件,即可在控制台里使用po命令打印出model的属性和值

2.1.8 给category添加属性的小技巧

    这是运用到了对象关联, 如果不会的请看这篇文章: 时空传送门

.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     便捷开发宏定义

2.2.1 运行时判断运行版本宏

Tufu

///运行时判断运行版本

#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  摒弃函数提示

///摒弃函数提示

#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     视图调试

ios中的视图调试(ios8苹果引入了强大的新技术,不可不看)

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

2.3.1 ios8以前调试控制台命令recursiveDescription

    在ios8以前,我们想要进行ui实时调试,可以依赖的技术手段有:

     1、用xcode启动app,然后点击xcode暂停运行按钮,然后在调试控制台输入下面语句:

po [[UIWindow keyWindow] recursiveDescription]

    然后就可以看到完整的UI结构和层级关系,类似如下:

<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]可以看到当前view下的ui结构,示例如下:

<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以后,苹果引入了新的技术手段支持我们进行实时ui调试;使用xcode运行app过程中,按下底部的Debug View Hierarchy 按钮,或者从菜单中选择Debug > View Debugging > Capture View Hierarchy 来启动视图调试:

        启动视图调试后,Xcode会对应用程序的视图层次拍一个快照并展示三维原型视图来探究用户界面的层级。该三维视图除了展示app的视图层次外,还展示每个视图的位置、顺序和视图尺寸,以及视图间的交互方式。

        该调试工具非常强大,结合storyboard一起使用可以很好的支撑ios开发的页面布局调整/性能优化等需求,具体的功能这里不一一展开,请开发人员在使用中进行总结和摸索。

2.3.3 第三方工具
2.3.3.1  Flipboard/FLEX

https://github.com/Flipboard/FLEX

Flipboard开源应用内调试工具FLEX

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

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

        如果打开了ARC或垃圾回收模式,在程序中发消息给以及重新分配的对象,将会引起程序崩溃。这时定位崩溃原因将非常困难,因为出问题的对象已经重新分配了。一个解决的方法就是要求Xcode将对象设置为“僵尸”,而不是重新分配。当给僵尸对象发送消息时,会抛出一个可描述的异常,且调试器会在出错代码行中断下来哦。下面看看如何打开“僵尸”模式喽:

        依次选择Xcode菜单: Product->Edit Scheme,进入Diagnostics窗口,勾选Zombie Objects选项即可:

2.4     便捷调试类定义

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获取,虽然:当这个变量是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 一个通用回调的简单示例(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回调

 *

 *  @param viewControllerActionBlock block的参数有view本身,状态码,键值对。

 */

- (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回调

*

*  @param viewControllerActionBlock block的参数有view本身,状态码,键值对。

*/

- (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, 参数都是通用的本身,状态码,字典.(灰神提供)

2.4.4 自定义弱关联对象(weak associated objects)

    不幸的是,关联对象不支持弱引用。 幸运的是,很容易实现。你只需要一个简单的类包装与弱引用一个对象.

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

设置与获取

Objective-C

// 设置弱引用关联

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

//获取弱引用关联

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

// 设置弱引用关联

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

//获取弱引用关联

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

2.4.5 动态调用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崩溃调试技巧

3.1     APP启动后崩溃调试

4     兼容性处理

4.1     系统定义宏

4.1.1 __OSX_AVAILABLE_BUT_DEPRECATED宏

        我们在开发的过程中会发现某些方法被deprecated了,这是因为这些方法已经被更好的方法代替了,或者是这些放在在当初设计的时候考虑不全面等。

__OSX_AVAILABLE_BUT_DEPRECATED() 宏说明,在某个版本开始引进一个方法,

    但是在某个版本之后废弃了。

__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0,__MAC_10_5,__IPHONE_NA,__IPHONE_NA)

    在mac os x 10.0 开始引进这个方法,但是在10.5之后废弃了,ios上从来没只支持过。

    我们可以自己写一些方法

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

    这个函数在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

    所以根据这点,我们可以处理在不同版本之间某些方法的切换

 #ifdef __IPHONE_6_1     methodOne;  #else     methodTwo;  #endif

4.2     系统版本判断

4.2.1  IOS开发中如何区分IOS版本

// 当前系统支持的最小版本

__IPHONE_OS_VERSION_MIN_REQUIRED

// 当前系统支持的最大版本

__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     代码基础

5.1     数据类型相关

5.1.1 Objective-C中的instancetype和id区别

    instancetype的作用,就是使那些非关联返回类型的方法返回所在类的类型!

1、相同点

    都可以作为方法的返回类型

2、不同点

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

②instancetype只能作为返回值,不能像id那样作为参数

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     性能优化

6.1     图片资源读取优化

6.1.1 iOS图片内存优化(博文)内存优化经验(from 灰灰)

解决步骤:instrument调试后,发现没被释放的全是imageIO,差不多就知道了,把读图的方式,从[UIImage imageNamed:@”“],改成imageWithContentsOfFile,就可以了。

问题原因:imageNamed读取图片的方法,会缓存在内存中,所以较大的图片,还是用imageWithContentsOfFile。?

Tip1:.xcassets里的图片无法用imageWithContentsOfFile读取;?

Tip 2:imageWithContentsOfFile读取图片需要加文件后缀名如png,jpg等;?

灰神内存优化链接地址点此

7     参考链接

iOS SDK:那些关于iOS调试的技巧

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

iOS自定义NSLog日志

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

iOS编程高性能之路-自定义宏总结

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-10-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1     工程配置类
    • 1.1     添加预编译文件
      • 1.2     给SDK头文件加权限
      • 2     调试技巧
        • 2.1     日志打印类
          • 2.1.1 让Xcode的控制台支持LLDB类型的打印
          • 2.1.2 Objective-C自定义NSLog宏
          • 2.1.3 调试宏__func__
          • 2.1.4 WriteLog类
          • 2.1.5 在控制台里打印controller的层级
          • 2.1.6 在控制台里打印view的层级
          • 2.1.7 在debug模式下的控制台里使用po命令打印对象的属性和值
          • 2.1.8 给category添加属性的小技巧
        • 2.2     便捷开发宏定义
          • 2.2.1 运行时判断运行版本宏
          • 2.2.2  公共库f形式的公共前缀
          • 2.2.3  摒弃函数提示
          • 2.2.4  自定义log提示
          • 2.2.5  release版本屏蔽log
          • 2.2.6 用宏定义检测block是否可用!
          • 2.2.7 使用ARC和不使用ARC(from 夏夏)
          • 2.2.8 读取本地图片(from 夏夏)
        • 2.3     视图调试
          • 2.3.1 ios8以前调试控制台命令recursiveDescription
          • 2.3.2 ios8/xcode6中Debug View Hierarchy功能
          • 2.3.3 第三方工具
          • 2.3.4 Xcode使用心得03:打开僵尸(Zombie)模式
        • 2.4     便捷调试类定义
          • 2.4.1 AmIBeingDebugged(from mattt)
          • 2.4.2 检查void *实例变量(from mattt)
          • 2.4.3 一个通用回调的简单示例(from 灰灰)
          • 2.4.4 自定义弱关联对象(weak associated objects)
          • 2.4.5 动态调用block(黑魔法)
      • 3     APP崩溃调试技巧
        • 3.1     APP启动后崩溃调试
        • 4     兼容性处理
          • 4.1     系统定义宏
            • 4.1.1 __OSX_AVAILABLE_BUT_DEPRECATED宏
            • 4.1.2  __OSX_AVAILABLE_STARTING
            • 4.1.3  __IPHONE_OS_VERSION_MIN_REQUIRED
            • 4.1.4  __MAC_OS_X_VERSION_MIN_REQUIRED
            • 4.1.5  __IPHONE_X_X
          • 4.2     系统版本判断
            • 4.2.1  IOS开发中如何区分IOS版本
        • 5     代码基础
          • 5.1     数据类型相关
            • 5.1.1 Objective-C中的instancetype和id区别
            • 5.1.2 weakSelf与strongSelf宏定义写法
        • 6     性能优化
          • 6.1     图片资源读取优化
            • 6.1.1 iOS图片内存优化(博文)内存优化经验(from 灰灰)
        • 7     参考链接
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档