说我有以下内容:
@interface MyClass : NSObject { NSString* _foobar; }
@property (nonatomic, retain) NSString* foobar;
@end
@implementation MyClass
@dynamic foobar;
- (void) setFoobar:(NSString*)fbSet; { [_foobar release]; _foobar = [fbSet retain]; }
- (NSString*) foobar; { return _foobar; }
@end
Run Code Online (Sandbox Code Playgroud)
然后:
MyClass* mcInst = [[[MyClass alloc] init] autorelease];
NSLog(@"I set 'foobar' to '%@'", (mcInst.foobar = @"BAZ!"));
Run Code Online (Sandbox Code Playgroud)
查看返回值-[MyClass setFoobar:],可以假设此行将打印I set 'foobar' to '',因为赋值似乎不返回任何内容.
但是 - 幸运的是 - 这个赋值按预期运行,代码打印出来I set 'foobar' to 'BAZ!'.不幸的是,这感觉就像一个矛盾,因为调用的setter的返回值掩盖了赋值返回赋给它的值的事实.起初我认为这mcInst.foobar = @"BAZ!";是两个调用而不是一个块:首先是setter,然后是getter来收集返回值.但是,通过NSLog …
无论如何在运行时加载一个目标c脚本,并针对当前iPhone应用程序中的classes/methods/objects/functions运行它?
主要注意:我想这样做的主要原因是允许我快速构建一个应用程序原型,然后,在我完成一个主要的原型设计阶段后,取出我正在编写的脚本并在构建时编译它们.我从来没有计划在其中运送带有客观c解释器的应用程序.
我问的原因是我一直在玩iPhone蜡,一个可以嵌入到iPhone应用程序中的lua解释器,它的工作非常好,从某种意义上说,你的目标中公开可用的任何对象/方法/功能C代码自动桥接,并在lua中可用.
这使您可以通过简单地将应用程序的核心设置为用户文档目录中的lua文件来快速构建应用程序原型.只需重新加载应用程序,您就可以测试对lua文件的更改,而无需在XCode中重建应用程序 - 节省大量时间!
但是,有了Apples最新的3.1.3 SDK的东西,它让我觉得做这种类型的快速原型的最安全的方法是如果你可以使用Objective C作为解释代码......这样,最糟糕的情况,你可以只需在发布之前将其编译到您的应用中.我听说lua源代码可以编译成字节代码,并在构建时链接,但我认为最终安全的事情是如果脚本源是在客观c,而不是lua.这样,无论如何,您的来源始终是客观的.
如果有任何关于如何在iPhone应用程序中嵌入Objective C Interpreter的示例,这会让我想知道(我已经搜索过,但没有提出任何内容)?这将允许您根据二进制文件中内置的当前类快速构建应用程序原型,并且,当您即将部署应用程序时,而不是通过in app解释器运行类,而是编译它们.
使用iPad和OS 4,蓝牙和虚拟键盘可以与iPhone和iPad配合使用......这将使这种类型的快速原型设计更有用,至少在开发时间.例如,如果您的应用程序内置了解释器并将其放在iPad上,则可以在旅途中对解释器进行编码,而无需XCode.对我而言,将源恢复为"苹果批准"状态的最有用方法是脚本是否为Objective C.
这个人想出了一个非常简洁的工具来生成类依赖图 - 但是,它依赖于解析你的源代码并寻找#import指令.
这很整洁,但我有很多问题.其中最重要的是它不考虑导入的导入,也不考虑前缀标题,也不考虑导入所引用的文件中的类是否实际被使用.
我想做更类似的事情class-dump并检查存储在Mach-O文件中的Objective-C元数据,以生成类依赖关系的内存中表示.
我不想从头开始做这个,所以我想知道:
为了简化,假设我有这样的功能
void myFunc(id _self, SEL _cmd, id first, ...)
{
}
Run Code Online (Sandbox Code Playgroud)
在那个方法中,我想在_self的超类上调用实现(imp).我可以使用以下代码访问IMP:
Class class = object_getClass(_self);
Class superclass = class_getSuperClass(class);
IMP superimp = class_getMethodImplementation(superclass, _cmd);
Run Code Online (Sandbox Code Playgroud)
现在,我怎么能打电话给那个imp?
这是摘录自Objective-C runtime programming guide:
创建新对象时,将分配其内存,并初始化其实例变量.对象变量中的第一个是指向其类结构的指针.这个名为isa的指针使对象可以访问它的类,并通过该类访问它继承的所有类.
isa声明NSObject如下:
Class isa;
Run Code Online (Sandbox Code Playgroud)
反过来Class只不过是指向结构的指针
typedef struct objc_class *Class;
Run Code Online (Sandbox Code Playgroud)
现在让我们来看看这个结构:
struct objc_class {
Class isa;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif
}
Run Code Online (Sandbox Code Playgroud)
我们可以看到,在最新版本的Objective-C中,指向超类的指针(以及结构的所有其余成员除了另一个成员之外)都不可用.
所以我的问题是如果super_class指针不可用,对象如何才能访问其超类?是否可以通过另一个isa指针访问超类?但究竟是怎么回事?这个怎么运作?有人能解释一下吗?
我想构建一个没有Foundation的简单Objective C程序.我试过了:
#include <stdio.h>
@interface Foo{
char * bar;
}
-(void)hello;
@end
@implementation Foo
-(void)hello {
printf("Hello world!");
}
@end
int main(){
Foo * foo = [Foo alloc];
return 0;
}
Run Code Online (Sandbox Code Playgroud)
然后它告诉我Foo may not respond to +alloc和autorelease called without pool...
如何在不使用allocFoundation的情况下初始化对象?
Objective-C @encode生成C字符串来表示任何类型,包括基元和类,如下所示:
NSLog(@"%s", @encode(int)); // i
NSLog(@"%s", @encode(float)); // f
NSLog(@"%s", @encode(CGRect)); // {CGRect={CGPoint=ff}{CGSize=ff}}
NSLog(@"%s", @encode(NSString)); // {NSString=#}
NSLog(@"%s", @encode(UIView)); // {UIView=#@@@@fi@@I{?=b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b6b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b3b1b1b1b2b2b1}}
Run Code Online (Sandbox Code Playgroud)
因此,我可以使用一个有意义的类(包含类名称)编码@encode(ClassName),但它的格式与泛型的编码相同struct(如上例所示).
现在,我的问题是,给定任何(当然有效)类型编码,是否可以找出编码是否是Objective-C类,如果是,那么获取Class对应于该编码的对象?
当然,我大概可以只尝试解析类名出的编码类型,并从使用获取类NSClassFromString,但只是听起来并不像正确的方式去做,或者特别的性能效率.这真的是实现这一目标的最佳方式吗?
给出以下代码:
return TyphoonDefinition.withClass(AppDelegate.classForCoder()) {
(definition) in
definition.injectProperty("assembly")
})
Run Code Online (Sandbox Code Playgroud)
...有必要使用.classForCoder(),如同.class()被击倒.与简单相比,这当然不直观.class().有没有提供更好的可读性的替代方案?
虽然可以setMyProperty:在obj-c中替换方法,但我想知道如何快速进行?
例如我要替换UIScrollView::setContentOffset::
let originalSelector: Selector = #selector(UIScrollView.setContentOffset)
let replaceSelector: Selector = #selector(UIScrollView.setContentOffsetHacked)
...
Run Code Online (Sandbox Code Playgroud)
...但是执行后originalSelector包含setContentOffset:animaed。那么,如何将属性的设置方法传递给selector?
Swift 编译器为带有块的 swift 方法生成的 Objective-C 方法编码似乎使用了任何地方都没有记录的语法。
例如方法:
func DebugLog2(message: String) async -> String
Run Code Online (Sandbox Code Playgroud)
有方法编码:
v32@0:8@"NSString"16@?<v@?@"NSString">24
并且文档中至少有三个字符("、<和)未涵盖:>
该类NSMethodSignature也不喜欢这种编码:
[NSMethodSignature signatureWithObjCTypes:"\"NSString\"16@?<v@?@\"NSString\">24"];
Run Code Online (Sandbox Code Playgroud)
结果是:
'+[NSMethodSignaturesignatureWithObjCTypes:]: '"NSString"16@?<v@?@"NSString">24'' 中不支持类型编码规范 '"'
我尝试查看 Swift 的代码,似乎有一种叫做“扩展方法类型编码”的东西:
但我在试图找出 Swift 代码库中方法类型编码生成的位置时迷失了方向。
不回答此问题的相关问题:
示例代码:
decodeProto()
@objc
class TestClass : NSObject {
@objc
func DebugLog(message: String) -> String {
print(message)
return message
}
@objc
func DebugLog2(message: String) async -> String {
do {
try await Task.sleep(nanoseconds: 1_000_000_000)
} catch {}
print(message); …Run Code Online (Sandbox Code Playgroud) objective-c ×9
swift ×3
gcc ×1
interpreter ×1
ios ×1
iphone ×1
mach-o ×1
runtime ×1
selector ×1