为什么swift nslog print不支持 Swift 对象

6800人阅读
[0]&Outline
& -- [1] id和Class
& -- [2]&动态地操作类
& -- [3]&实例化
[1] id和Class
在Objective-C中有一个特别的数据类型作为对象标识符:id,可以指向任何类型的对象。
通过 “可以指向任何类型的对象” 这一描述,猜想id实际上是指向Objective-C对象系统中的基类(继承体系中的祖先结构)的指针,在运行时是指向对象内存布局的基类部分。
第一眼看到id数据类型,我联想到了Python中的PyObject结构:
typedef struct _object {
struct _typeobject *ob_
该数据类型也是Python对象系统中的祖先类型,不过与id相对应的应该是PyObject *类型。
id数据类型是一个指向struct objc_object结构的指针:
typedef struct objc_class *C
typedef struct objc_object {
更确切地说,id是指向Class类型的指针,而Class又是指向struct objc_class结构的指针:
struct objc_class {
struct objc_class *
struct objc_class *super_
const char *
long instance_
struct objc_ivar_list *
struct objc_method_list **methodL
struct objc_cache *
struct objc_protocol_list *
至此,可以看到Objective-C对象系统的基石:struct objc_class结构:
isa指针:指向该对象所属类型的类型对象(Class Object)。在Objective-C中,类也是用对象来表示的,而类的isa指针指向它的metaclass(存储静态成员变量和类方法)。
super_class指针:指向父类。
name:类名称。
version:类的版本信息。
info:运行期使用的标志位,比如0x1(CLS_CLASS)表示该类为普通class,0x2(CLS_META)表示该类为
metaclass。
instance_size:实例大小,即内存所占空间。
ivars:指向成员变量列表的指针。
methodLists:根据标志位的不同可能指向不同,比如可能指向实例方法列表,或者指向类方法列表。
cache:因为Objective-C的消息转发需要查找dispatch table甚至可能需要遍历继承体系,所以缓存最近使用的方法。
protocols:类需要遵守的协议。
[2] 动态地操作类
由上知道了类也是一种对象,那么类对象也有一种类型,这种类型就是类的metaclass,因此类方法其实就是metaclass的成员方法,类和metaclass是配套出现的。
那么metaclass的isa指针和super_class指针怎么指向的呢?
如果metaclass对应基类,那么它的isa指向自身、super_class指针指向对应的类(基类);如果不是则isa指针指向基类的metaclass、super_class指针指向父类的metaclass。
基类的isa指针为nil。
这不禁让我又想起了Python中类似的设计思想,比如整型数字2的类型是PyIntObject,而PyIntObject类的类型是PyTypeObject,PyTypeObject的类型是PyTypeObject。最终止于此。
同样地,Python中也有metaclass的存在。
知道了类的表示结构,我们可以动态地对类进行操作,加深理解。
Created by Jason Lee on 12-2-17.
Copyright (c) 2012年 XXX. All rights reserved.
#import &Foundation/Foundation.h&
#import &objc/objc.h&
#import &objc/runtime.h&
void selfIntro(idself, SEL_cmd);
int main (int argc, constchar * argv[])
@autoreleasepool {
//Create class & metaclass as a pair
Class demoClass = objc_allocateClassPair([NSObjectclass], &NSDemo&, 0);
BOOL isOk = NO;
//&v@:& indicates the function type : v - void, @ - object, : - SEL
//向methodLists指向添加数据
isOk = class_addMethod(demoClass, @selector(intro), (IMP)&selfIntro, &v@:&);
isOk == YES ? nil : NSLog(@&failed on class_addMethod\n&);
//向ivars指向添加数据
isOk = class_addIvar(demoClass,&myVar&, sizeof(id), log2(sizeof(id)), &@&);
isOk == YES ? nil : NSLog(@&failed on class_addIvar\n&);
objc_registerClassPair(demoClass);
id demo = class_createInstance(demoClass, 0);
if ([demo respondsToSelector:@selector(intro)]) {
[demo performSelector:@selector(intro)];
object_setInstanceVariable(demo, &myVar&, nil);
void *outValue = (void *)0x1;
object_getInstanceVariable(demo, &myVar&, &outValue);
if (nil == outValue) {
NSLog(@&Hello,nil\n&);
object_dispose(demo);
void selfIntro(idself, SEL_cmd) {
NSLog(@&selfIntro\n&);
Class isa = self-&
//At first, isa is class NSDemo
while (1) {
if (isa == isa-&isa) {
//Finally, NSObject's metaclass points to itself
NSLog(@&%p, %@&, isa, objc_getMetaClass(class_getName([isa class])));
NSLog(@&%p, %@&, isa, objc_getMetaClass(class_getName([isa class])));
isa = isa-& //Then, isa is assigned to NSDemo's metaclass
[3] 实例化
要实例化出一个对象,需要根据类的定义来进行。类的定义包括类名称、数据和操作数据的方法。
编译过程,类的信息会被记录下来,供runtime system使用,同时编译器会为每个类创建唯一的一个对象来表示它:class object。如果从功能上说,class object也是factory object,它能够执行类方法,负责创建实例。
从这个角度来看,我在思考class object是否就是metaclass,但是不能确认。
Apple官方文档TOCPL中Class Objects一章有这么一句,“a class object keeps the prototype of a class instance”,但metaclass并不能作为实例原型。
于是我认为class object是运行时class和metaclass结合起来的受限表现,能够访问编译器捕捉下来的类信息,没有成员变量,不能调用成员方法,但是可以执行类方法。
从源码层次来看,class object是由类名来表示,比如下述代码中:
int version = [NSString version];
NSString代表着class object。
首先,class object会被runtime system发送initialize消息进行初始化,让其做好运行时的准备,比如初始化静态变量。
之后,可以调用class object的方法(类方法)alloc来为新的实例对象分配内存空间,将其所有变量初始化为0,isa指针指向所属类。
最后再调用init函数进行必要的初始化。
写到这里的时候,突然要变更办公位置,思路被打断了,就先写到这里。
最后,留一个在SO上面看到的问题,我也疑惑,只能有几分猜测:
[这篇文章是我对SO上的问题的解答:]
[Last Updated]
Jason Lee @ 杭州
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1300629次
积分:13421
积分:13421
排名:第650名
原创:193篇
评论:853条
文章:14篇
阅读:27386
文章:16篇
阅读:237129
(1)(1)(2)(2)(1)(1)(1)(1)(5)(3)(3)(1)(1)(2)(2)(4)(1)(1)(1)(3)(1)(3)(1)(1)(12)(5)(4)(4)(5)(10)(4)(3)(1)(1)(18)(5)(1)(4)(3)(1)(2)(1)(1)(1)(1)(1)(6)(6)(2)(4)(8)(4)(2)(10)(11)(7)(3)(3)(1)(6)iOS技术(33)
1、首先在Build&Settings中找到&Swift&Compliler-Custom&Flags,并添加以下参数&-DDEBUG参数,如下图:
2、创建Log.swift文件并实现下面的函数
&&&&func&NKLog(message:&String){
&&&&&&&&NSLog(message)
&&&&func&NKLog(message:&String){
//&&&&&&&&NSLog(message)
3、工程中调用就调用NKLog()就OK了。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:14278次
排名:千里之外
原创:22篇
转载:13篇
(3)(4)(3)(11)(7)(7)问题已关闭
过于个人化、场景化
现行社区规则下,提问需要满足:其他人可能遇到相似问题,或问题的解决方法对其他人有所助益。具体标准请参考。
一个关于NSLog和对象释放谁先被程序执行的问题?
下面是我编写的Objective代码:&br&main.m&br&#import &Foundation/Foundation.h&&br&#import &XYZPerson.h&&br&&br&int main(int argc, const char * argv[])&br&{&br&&br&
@autoreleasepool {&br&&br&
XYZPerson *firstPerson = [XYZPerson personWithFirstName:@&Ronnie& lastName:@&O'Sullivan& dateOfBirth:nil];&br&&br&
[firstPerson sayHello];&br&&br&
firstPerson =&br&&br&
NSLog(@&The firstPerson object has been delloced from the memory&);&br&&br&&br&&br&
return 0;&br&}&br&XYZPerson.h&br&&br&#import &Foundation/Foundation.h&&br&&br&@interface XYZPerson : NSObject&br&&br&@property
NSString *firstN&br&@property
NSString *lastN&br&@property NSDate *dataOfB&br&&br&-(void)sayH&br&-(void)saySomething:(NSString *)greeting firstName:(NSString *)aFirstName lastName:(NSString *)aLastN&br&-(id)initWithFirstName:(NSString *)aFirstName lastName:(NSString *)aLastName dateOfBirth:(NSDate *)aDOB;&br&&br&+(id)personWithFirstName:(NSString *)aFirstName lastName:(NSString *)aLastName dateOfBirth:(NSDate *)aDOB;&br&&br&@end&br&XYZPerson.m&br&&br&//&br&//
XYZPerson.m&br&//
LearningObjective-c&br&//&br&//
Created by 爱吃米的小老鼠 on 13-8-21.&br&//
Copyright (c) 2013年 指尖留情. All rights reserved.&br&//&br&&br&#import &XYZPerson.h&&br&&br&@implementation XYZPerson&br&&br&-(void)sayHello&br&{&br&
[self saySomething:@&Hello, World!& firstName:self.firstName lastName:self.lastName];&br&}&br&&br&-(void)saySomething:(NSString *)greeting firstName:(NSString *)aFirstName lastName:(NSString *)aLastName&br&{&br&
NSLog(@&%@,%@ %@&, greeting, aFirstName, aLastName);&br&}&br&&br&-(id)initWithFirstName:(NSString *)aFirstName lastName:(NSString *)aLastName dateOfBirth:(NSDate *)aDOB&br&{&br&
self = [super init];&br&&br&
if(self){&br&
_firstName = aFirstN&br&
_lastName = aLastN&br&
_dataOfBirth = aDOB;&br&
}&br&&br&&br&}&br&&br&-(id)init&br&{&br&
return [self initWithFirstName:@&John& lastName:@&Doe& dateOfBirth:nil];&br&}&br&&br&-(void)dealloc{&br&
NSLog(@&XYZPerson is being deallocated&);&br&}&br&&br&&br&+(id)personWithFirstName:(NSString *)aFirstName lastName:(NSString *)aLastName dateOfBirth:(NSDate *)aDOB&br&{&br&
return [[self alloc] initWithFirstName:aFirstName lastName:aLastName dateOfBirth:aDOB];&br&}&br&@end&br&问题是这样的,根据我的理解,当firstPerson强指针被设为NULL时,我觉得首先指向的XYZPerson对象就会执行dealloc的方法,然后再执行NSlog语句。&br&但是根据XCODE的输出,结果却是这样的:&br&&b& 21:45:18.275 LearningObjective-c[] Hello, World!,Ronnie O'Sullivan&/b&&br&&b& 21:45:18.277 LearningObjective-c[] The firstPerson object has been delloced from the memory&/b&&br&&b& 21:45:18.277 LearningObjective-c[] XYZPerson is being deallocated&/b&&br&&b&为什么结果最后NSLOG会先出现然后再执行XYZPerson对象的释放呢?&/b&
下面是我编写的Objective代码:main.m#import &Foundation/Foundation.h&#import "XYZPerson.h"int main(int argc, const char * argv[]){
@autoreleasepool {
XYZPerson *firstPerson = [XYZPerson personWithFirstName:@"Ronnie" lastName:@"O'Sullivan" dateOfBirth:nil];
[firstPerson sayHello];
firstPerson =
NSLog(@"The firstPerson object has been delloced from the memory");
return 0;}XYZPerson.h#import &Foundation/Foundation.h&@interface XYZPerson : NSObject…
你把@autoreleasepool 给去了看看
autoreleasepool在处理这个对象,分配的对象放入pool, 不管你现在怎么折腾,等这一轮NSLoop结束之后自动释放pool里面的所有对象。这个跟arc和retain/release是分开的另一套机制,为了简化内存管理而建立的autorelease pool这么一套机制。------------------你说的这个设置为nil之后释放,是针对arc而言。arc是在设置为nil之后,自动插入release的代码,而release代码执行时看到引用计数为0,就调用dealloc了。----------------------------------------------一块内存,只要没有去释放它,他就会活得很好。那么谁去释放它、什么时机去释放它呢?传统的c/c++的做法是,栈上的,超出了作用域就释放;堆上的,应用程序的代码自己去释放。后来,堆上的对象越来越多,就不得不搞得更复杂一些:java等语言的GC, 是定期或者不定期的由捡垃圾的清洁工(GC线程)来释放。那么到底是不是垃圾,也由GC线程来判断。这个代价相当大,所以GC线程是很低的优先级来执行。判断是不是垃圾,这事儿其实很复杂,光靠引用计数是不够的,因为经常会发生循环引用的问题。早期某个版本的JVM还有这么一种GC的方式:准备另外一块很大的内存,把所有引用到的对象都复制过去,然后把原来的内存全部回收。而objective c为了保持高效率,采用的是半自动的retain/release的方式。说真的,非常不好用,我一直没弄明白~~~甚至我都不知道自己没弄明白,以为很简单,然后用instrument一调试,才发现我用错了,到处都是内存漏洞~~~可是苹果的一个高手,发明了一套静态分析代码,在编译的时候发现内存漏洞的技术。只要按shift-command-B, 就会帮你分析内存漏洞。后来就搞出了苹果自己的ARC, 这个可不是GC那一套,而是靠这种静态分析内存漏洞的技术,来帮你自动在需要的地方插入retain/release等等代码。---------------------pool里面的对象,都有pool去引用啊,引用计数并不会变为0.pool里面的对象是在跑出autoreleasepool{}作用域的时候自动释放的,所以arc不用多管闲事去再插release的代码。
已有帐号?
无法登录?
社交帐号登录主题信息(必填)
主题描述(最多限制在50个字符)
申请人信息(必填)
申请信息已提交审核,请注意查收邮件,我们会尽快给您反馈。
如有疑问,请联系
傻丫头和高科技产物小心翼翼的初恋
如今的编程是一场程序员和上帝的竞赛,程序员要开发出更大更好、傻瓜都会用到软件。而上帝在努力创造出更大更傻的傻瓜。目前为止,上帝是赢的。个人网站:。个人QQ群:、
个人大数据技术博客:
CSDN &《程序员》编辑/记者,我的邮箱
Swift 中的 NSLog 并不支持转义输出哦,目测这问题会变成面试题的。我们在开发中,如果直接使用NSLog打印对象,则会打印对象的指针(如下图)
但我们常常希望打印的是对象的属性的值,因此我们需要重写自定义类的description方法(打印日志时,对象会收到description消息,在description方法返回打印的字符串),如下:
-(NSString*)description{
return [NSString stringWithFormat:@&&%@: %p& {userId: %@ ,name: %@ ,image: %@}&,[self class],self,self.userId,self.name,self.image];
再次执行NSLog代码,打印的就是我们在description方法中返回的字符串了
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:48438次
积分:1123
积分:1123
排名:千里之外
原创:57篇
转载:13篇
评论:23条
(1)(5)(1)(2)(1)(9)(7)(3)(2)(1)(3)(1)(13)(17)(8)(1)

我要回帖

更多关于 ios swift nslog 的文章

 

随机推荐