【问题标题】:Using pointers in Objective C for NSMutableArray objects在 Objective C 中为 NSMutableArray 对象使用指针
【发布时间】:2011-11-14 04:37:19
【问题描述】:

在 cocoa-touch 中从 NSMutableArray 中检索对象时,下面的代码可以吗?我应该每次都分配([alloc])新的 Page 对象还是只是指向它好吗?之后我是否需要对 Page *pageObj 做任何事情,例如将其设置为 nil?

const char *sql = "insert into Page(Book_ID, Page_Num, Page_Text) Values(?, ?, ?)";
for (i = 0; i < ([[self pagesArray] count] - 1); i++) {
    if(addStmt == nil) {
        if(sqlite3_prepare_v2(database, sql, -1, &addStmt, NULL) != SQLITE_OK) {
            NSAssert1(0, @"Error while creating add statement. '%s'", sqlite3_errmsg(database));
        }
    }
    Page *pageObj = [[self pagesArray] objectAtIndex:i];
    if(pageObj.isNew) {
        sqlite3_bind_int(addStmt, 1, self.book_ID); 
        sqlite3_bind_int(addStmt, 2, pageObj.page_Number);  
        sqlite3_bind_text(addStmt, 3, [[pageObj page_Text] UTF8String], -1, SQLITE_TRANSIENT);
        if(SQLITE_DONE != sqlite3_step(addStmt)) {
            NSAssert1(0, @"Error while inserting data. '%s'", sqlite3_errmsg(database));
        }
        NSLog(@"Inserted Page: %i into DB. Page text: %@", pageObj.page_Number, pageObj.page_Text);
    }
    //Reset the add statement.
    sqlite3_reset(addStmt);                     
}

谢谢。我也知道这可能应该在交易中,但我还没有完全得到它的工作。

【问题讨论】:

    标签: objective-c cocoa-touch sqlite


    【解决方案1】:

    您声明指针的方式是正确的。您不需要 alloc,因为当您想要引用数组中的现有对象时,它会创建一个新对象。如果您要将引用保留在该方法之外,您可能希望保留它,但由于您只是暂时使用它,所以不要这样做。

    实际的指针变量将在每次循环中被销毁并重新创建,因此无需将其设置为 nil。即使您在循环之外声明了变量,只需将其分配给一个新对象就可以了。唯一一次将它设置为 nil 是当您释放存储在指针中的对象时(或者该对象可能在其他地方释放)。如果在这种情况下没有将其设置为 nil,则在对象被释放后,指针将引用无效的内存位置,通常会导致崩溃。

    我可以看到一个错误,您通过从计数中减去 1 来跳过 for 循环中数组中的最后一个元素。

    【讨论】:

      【解决方案2】:

      除了前面提到的计数错误,它看起来不错。

      就事务而言,我强烈建议将此写入循环封装在一个中。它将大大提高您的写入性能,我发现它也有助于内存使用。我使用以下类方法开始事务:

      + (BOOL)beginTransactionWithDatabase:(sqlite3 *)database;
      {
          const char *sql1 = "BEGIN EXCLUSIVE TRANSACTION";
          sqlite3_stmt *begin_statement;
          if (sqlite3_prepare_v2(database, sql1, -1, &begin_statement, NULL) != SQLITE_OK)
          {
              return NO;
          }
          if (sqlite3_step(begin_statement) != SQLITE_DONE) 
          {
              return NO;
          }
          sqlite3_finalize(begin_statement);
          return YES;
      }
      

      和这个结束交易:

      + (BOOL)endTransactionWithDatabase:(sqlite3 *)database;
      {
          const char *sql2 = "COMMIT TRANSACTION";
          sqlite3_stmt *commit_statement;
          if (sqlite3_prepare_v2(database, sql2, -1, &commit_statement, NULL) != SQLITE_OK)
          {
              return NO;
          }
          if (sqlite3_step(commit_statement) != SQLITE_DONE) 
          {
              return NO;
          }
          sqlite3_finalize(commit_statement);
          return YES;
      }
      

      我可能应该存储 SQL 语句以供以后重用,但这些事务语句的调用频率远低于我的其他查询。

      【讨论】:

      • 谢谢布拉德,我是否只是保持我上面的查询与您发布的一样,并将其包装在 beginTransaction 和 endTransaction 中?
      • 是的,在上面的代码之前放置一个 [YourClass beginTransactionWithDatabase:database] 和一个 [YourClass endTransactionWithDatabase:database],这应该是在单个事务中执行查询循环所需的全部内容。
      【解决方案3】:

      当然不是。您之前已经分配过它并且只是引用同一个对象。无需重新分配。此外,您不需要将其设置为 nil。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-02-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-10-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多