Почему этот экземпляр объекта изменяется? - PullRequest
0 голосов
/ 14 марта 2012

Я очень новичок в цели C, я только учусь. Я сделал учебник по techotopia «An_Example_SQLite_based_iOS_4_iPhone_Application_ (Xcode_4)», затем попытался реализовать его снова с помощью FMDB. (Я бы опубликовал ссылку на учебник, но это позволило мне опубликовать максимум 2 ссылки)

Проблема: в initWithFrame создаю eventDB. Затем в addEvent после нажатия клавиши содержимое eventDB.database изменяется. Это равно eventDB в initWithFrame и это в 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;
}

1 Ответ

0 голосов
/ 14 марта 2012

Вы фактически не сохраняете базу данных. В Objective-C вам нужно вручную сохранить объекты, особенно если они не являются свойствами. (например, name объявлено как свойство, database нет)

Сохранение означает, что вы владеете объектом. databaseWithObject сохраняет базу данных, но вызывает autorelease для нее, что обычно означает, что она удалит ссылку как можно скорее после завершения вызывающего метода.

В зависимости от вашей платформы, например OS X вместо iOS, вы можете включить GarbageCollection -feature. Это будет означать, что среда 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;

Пример метода установки, который вы бы вызывали вместо ручного назначения:

  • [self setDatabase:...]; вместо непосредственного присвоения значения database = ...

Методы установки, такие как setVariableName и методы получения, такие как variableName синтезируются для вас директивой @synthesize.

...