@Ilija:如果你发帖说你已经放手了,那么你还没有真正放手。;) 让我看看我是否可以澄清我的评论:
-(NSString *) album
{
return self->album;
}
-(NSDictionary *) albumAndArtist
{
return @{ @"album":self.album, @"artist":self.artist };
}
上面的album
方法是 Objective-C 编译器会自动为您生成的方法。* 该albumAndArtist
方法是我在回答您的原始问题时建议的。现在,如果您要求 Clang 将这两种方法降级为 C ( clang -rewrite-objc test.m -o test.cc
),您会得到如下结果:
static NSDictionary * _I_iTunesTrack_albumAndArtist_albumAndArtist(iTunesTrack * self, SEL _cmd) {
return ((NSDictionary *(*)(id, SEL, const id *, const id *, NSUInteger))(void *)
objc_msgSend)(objc_getClass("NSDictionary"), sel_registerName("dictionaryWithObjects:forKeys:count:"),
(const id *)__NSContainer_literal(2U, ((NSString *(*)(id, SEL))(void *)objc_msgSend)
((id)self, sel_registerName("album")), ((NSString *(*)(id, SEL))(void *)objc_msgSend)
((id)self, sel_registerName("artist"))).arr, (const id *)__NSContainer_literal(2U,
(NSString *)&__NSConstantStringImpl_test_m_0, (NSString *)&__NSConstantStringImpl_test_m_1).arr, 2U);
}
或者,用人类的术语来说,
-(NSDictionary *) albumAndArtist
{
id album = objc_msgSend(self, sel_registerName("album"));
id artist = objc_msgSend(self, sel_registerName("artist"));
id *values = calloc(2, sizeof(id)); values[0] = album; values[1] = artist;
id *keys = calloc(2, sizeof(id)); keys[0] = @"album"; keys[1] = @"artist";
Class dict_class = objc_getClass("NSDictionary");
id result = objc_msgSend(dict_class, sel_registerName("dictionaryWithObjects:forKeys:count:"), values, keys, 2);
free(values); free(keys);
return result;
}
检查一下:三个sel_registerName
s,一个objc_getClass
,三个objc_msgSend
s,两个calloc
s和两个free
s。album
与编译器生成的方法相比,这非常低效。
从技术上讲,编译器生成的album
方法如下所示:
-(NSString *) album
{
return objc_getProperty(self, _cmd,
__OFFSETOFIVAR__(struct iTunesTrack, album), /*atomic*/ YES);
}
但这只是因为它最初没有被声明为nonatomic
. 有关 的含义objc_getProperty
,请参见此处;但基本上,它比objc_msgSend
本来要快。)
显然albumAndArtist
会比 慢得多album
,因为它正在做所有额外的工作。但是——你问——如果我们把所有的工作都扔掉然后回来self.album
怎么办?好吧,生成的代码仍然比编译器为album
getter 生成的代码更复杂:
-(NSString *) albumAndArtist_stripped_down
{
// return self.album;
return objc_msgSend(self, sel_registerName("album"));
}
当您的程序调用myTrack.album
时,它会调用objc_msgSend
一次以确定它应该调用该album
方法,然后在album
它内部调用objc_getProperty
. 那是两个电话。(如果你数的话,三个selector_registerName("album")
。)
当您的程序调用myTrack.albumAndArtist_stripped_down
时,它调用objc_msgSend
一次以确定它应该调用该方法albumAndArtist_stripped_down
,然后调用第二次,objc_msgSend
然后调用. 那是三个电话。(如果算上五个。)objc_getProperty
selector_registerName
因此,对我来说,它albumAndArtist_stripped_down
的速度应该是其自身速度的两倍(或 5/3 的速度)album
。
至于原来的albumAndArtist
,仅通过计算函数调用,我预计它的速度大约是...的五倍,album
但当然它会比这慢得多,因为它至少进行了三个内存分配,而album
没有做任何事情。内存分配和清理非常昂贵,因为malloc
它本身就是一个复杂的算法。
我希望这可以为您解决问题。:)