为啥要更改此实例对象?

Posted

技术标签:

【中文标题】为啥要更改此实例对象?【英文标题】:Why is this instance object being changed?为什么要更改此实例对象? 【发布时间】:2012-03-13 20:39:39 【问题描述】:

我对目标 C 很陌生,我只是在学习。我完成了 techotopia 教程“An_Example_SQLite_based_ios_4_iPhone_Application_(Xcode_4)”,然后尝试使用 FMDB 再次实现它。 (我会发布教程的链接,但我最多只能发布 2 个链接)

问题:在initWithFrame 我创建eventDB。然后在addEvent 中,在按键之后,eventDB.database 的内容发生了变化。 This 是 eventDBinitWithFrame 和 this 是在 addEvent

#import "appTracker.h"
@implementation appTracker

- (id) initWithFrame:(NSRect)frameRect

    self = [super initWithFrame:frameRect];
    eventDB = [[appTrackerDB alloc] init];
    return self;



- (void) keyDown: (NSEvent *) event


    NSString *chars = [event characters];
    unichar character = [chars characterAtIndex: 0];
    if (character == 'A') 
        NSLog (@"Adding event");
        [self addEvent:@"test_arg"];            
    


- (void) addEvent: (NSString *) name

    [eventDB setName:name];
    [eventDB setPhone:name];
    [eventDB setAddress:name];
    [eventDB setStatus:name];
    [eventDB saveData];

...
@end

使用 GDB,我发现它在 main.m(由 XCode4 自动生成)中发生了变化:(不太确定这段代码的作用或它为什么存在)

    #import <Cocoa/Cocoa.h>

int main(int argc, char *argv[])

    return NSApplicationMain(argc, (const char **)argv);

我不熟悉目标 C。有人可以帮我弄清楚为什么我的 eventDB.database 对象被更改了吗?我可能没有正确管理一些内存或完全误解了您应该如何执行此操作。任何帮助将不胜感激。

eventDB 是一个实例:

#import <Foundation/Foundation.h>
#import "FMDatabase.h"

@interface appTrackerDB : NSObject 
    NSString *name;
    NSString *address;
    NSString *phone;
    NSString *status;
    NSString *databasePath;
    FMDatabase *database;

谢谢!

还有 [eventDB saveData] 是:

- (void) saveData

    [database executeUpdate:@"insert into user (name, address, phone) values(?,?,?)",
     name, address, phone,nil];

并使用以下命令创建数据库:

@implementation appTrackerDB
@synthesize name,address,status,phone;

- (id)init

    self = [super init];
    if (self) 
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *docsPath = [paths objectAtIndex:0];
        NSString *path = [docsPath stringByAppendingPathComponent:@"database.sqlite"];

        database = [FMDatabase databaseWithPath:path];
        [database open];

        [database executeUpdate:@"create table IF NOT EXISTS user(ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT, ADDRESS TEXT, PHONE TEXT)"];
        if ([database hadError]) 
            NSLog(@"DB Error %d: %@", [database lastErrorCode], [database lastErrorMessage]);
        
        name = @"TEST";
    

    return self;

【问题讨论】:

你不想改变它吗?我的意思是您在调用 addEvent 时设置名称和地址属性,这会更改对象。还是您在谈论替换对象? (例如指针值发生变化)也许你应该详细说明你的问题到底是什么。 我不希望eventDB.database 的内容发生变化。我不会改变那些。 aehm... 那么 [eventDB saveData];如果它没有将数据保存到数据库中,该怎么办? 对不起,我看到了混乱。问题不是数据库的内容发生了变化,而是对数据库的引用发生了变化。如果您查看问题中的两张图片,您就会明白我的意思。也只是为了完整性,我添加了 saveData 的代码。 好的,我明白你的意思了。你是如何初始化实际的 FMDatabase 的?该文档提出了三种不同的方法,可以解释您的问题。 【参考方案1】:

您实际上并没有保留数据库。在 Objective-C 中,您需要手动保留对象,尤其是当它们不是属性时。 (例如,name 被声明为属性,database 不是)

保留意味着您拥有该对象。 databaseWithObject 保留了数据库,但在上面调用了autorelease,这通常意味着调用方法完成后,它会尽快删除引用。

取决于您的平台,例如OS X 而不是 iOS,您可以启用 GarbageCollection 功能。这意味着,OSX/Objective-C 环境将为您完成大量的内存管理。但是要使这有任何用途,您需要将相关的实例变量声明为属性在它们上使用适当的 setter 和 getter 方法。

这是一个属性声明的示例 (appTrackerDB.h):

#import <Foundation/Foundation.h>
#import "FMDatabase.h"

@interface appTrackerDB : NSObject 
  /*
    These are only necessary when 
    using iOS-Versions prior to
    iOS 4, or if you really
    need to manipulate the values 
    without utilizing the setter-/getter-
    methods.
  */
  NSString *name;
  NSString *address;
  NSString *phone;
  NSString *status;
  NSString *databasePath;
  FMDatabase *database;

@property (retain) NSString *name,*address;
@property (retain) NSString *phone,*status,*databasePath;
@property (retain) FMDatabase *database;

appTrackerDB.m

@implementation appTrackerDB
@synthesize name,address,status,phone;
@synthesize databasePath,database;

您可以调用而不是手动分配的示例 setter 方法是:

[self setDatabase:...]; 而不是直接赋值database = ...

setVariableName 这样的setter 方法和像variableName 这样的getter 方法 由@synthesize 指令为您合成。

【讨论】:

我用@property (retain, nonatomic) FMDatabase *database;把它变成了一个属性,合成了它,但问题仍然存在。我现在必须手动保留它吗? 您必须在 init 中调用 [self setDatabase:[FMDatabase databaseWithPath:path]]; 而不是 database =.. 变体 做到了!谢谢。这有什么不同? 此方法称为 setter,可以像手动设置变量一样设置变量,但也保留对象。对于不想深入了解 Objective-c 机制的人来说,这是一种更简单的方法(大多数人不需要) 由于这是在 OSX 上,是否有一些垃圾收集设置我可以启用,这样我就不必使用[self setDatabase:...];

以上是关于为啥要更改此实例对象?的主要内容,如果未能解决你的问题,请参考以下文章

为啥在我的反应形式中此 FormArray 更改后,我从 JSON 文件中检索对象时收到此错误消息?

为啥我的 Java 对象在方向更改后引用旧活动?

GCP 计算实例上的部署失败,为啥从 Gitlab 推送更改

为啥更改 ItemsSource 时 DataGrid 不更新?

为啥我不能在不更改或保存更改的情况下关闭此模式?

为啥我不能更改 QMap 中的 Qvariant 值?