Obj-C 作用域/等效于 C# ID是可置的、"使用"的还是C++自动变量?



我想创建绑定到作用域的obj c对象,这样对象就知道何时进入/退出作用域。

这是一个ARC环境。

目标是创建一些日志实用程序,这些实用程序可以轻松地生成封装进程的日志,如以下所示:

onHttpRequest {
    deduce encoding - found UTF-8!
    parsing xml took 0.08 seconds
    unknown request found... sending error.
    sendingResponse took 0.02 seconds.
} (0.10 seconds)

这在过去的C++和C#中是很容易的。现在我正在学习obj-c,想不出一种干净的方法。

在C++中,这很容易使用auto变量:

struct ScopedLogMessage
{
    ScopedLogMessage(std::string msg) { debugPrint(indentStr + msg + newline); indent ++; }
    ~ScopedLogMessage() { indent --; debugPrint(indentStr + "}" + newline); }
}
void onHttpRequest()
{
    ScopedLogMessage x("onHttpRequest");
    debugPrint("deduce encoding ...");
    debugPrint("more stuff ....");
}

或者在C#中,使用IDisposableusing(){}块:

class ScopedLogMessage : IDisposable
{
    public ScopedLogMessage(string msg) { debugPrint(indentStr + msg + newline); indent ++; }
    public void Dispose() { indent --; debugPrint(indentStr + "}" + newline); }
}
static void onHttpRequest()
{
    using(ScopedLogMessage x = new ScopedLogMessage("onHttpRequest"))
    {
        debugPrint("deduce encoding ...");
        debugPrint("more stuff ....");
    }
}

在objective-C中可以做类似的事情吗?

使用ARC,当变量超出范围时,编译器会自动保留和释放变量,因此代码如下所示:

NSLog(@"Logging at indent level 0");
{
    ScopedLogMessage* log1 = [[ScopedLogMessage alloc] initWithMessage:@"Begin nested operations"];
    [log1 debugLog:@"Logging at indent level 1"];
    {
        ScopedLogMessage* log2 = [[ScopedLogMessage alloc] initWithMessage:@"Another level of nested operations" parentLog:log1];
        [log2 debugLog:@"Logging at indent level 2"];
    }
    [log1 debugLog:@"Logging at indent level 1 again"];
}
NSLog(@"Logging at indent level 0 again");

输出将是:

Logging at indent level 0
Begin nested operations {
    Logging at indent level 1
    Another level of nested operations {
        Logging at indent level 2
    }
    Logging at indent level 1 again
}
Logging at indent level 0 again

ScopedLogMessage类的代码:

ScopedLogMessage.h

#import <Foundation/Foundation.h>
@interface ScopedLogMessage : NSObject
- (id)initWithMessage:(NSString*)message;
- (id)initWithMessage:(NSString*)message parentLog:(ScopedLogMessage*)parentLog;
- (void)debugLog:(NSString*)message;
@end

ScopedLogMessage.m

#import "ScopedLogMessage.h"
@interface ScopedLogMessage ()
@property ScopedLogMessage* parentLog;
@property int indent;
@end
@implementation ScopedLogMessage
- (id)initWithMessage:(NSString *)message {
    if (self = [super init]) {
        [self debugLog:[NSString stringWithFormat:@"%@ {", message]];
        self.indent = 1;
    }
    return self;
}
- (id)initWithMessage:(NSString *)message parentLog:(ScopedLogMessage *)parentLog {
    if (self = [super init]) {
        self.parentLog = parentLog;
        self.indent = parentLog.indent;
        [self debugLog:[NSString stringWithFormat:@"%@ {", message]];
        self.indent++;
    }
    return self;
}
- (void)dealloc {
    self.indent --;
    [self debugLog:@"}"];
}
- (void)debugLog:(NSString*)message {
#ifdef DEBUG
    NSString* indentString = [@"" stringByPaddingToLength:self.indent * 4 withString: @" " startingAtIndex:0];
    NSLog(@"%@%@", indentString, message);
#endif
}
@end

如您所见,dealloc方法是关键,相当于C#Dispose。如果没有ARC,您将被迫释放日志并在dealloc方法上调用[super dealloc]

希望能有所帮助。

最新更新