问题
I have read Where to put iVars in "modern" Objective-C? and some other questions, but I am still confused.
I am reading from https://www.raywenderlich.com/913/sqlite-tutorial-for-ios-making-our-app SQLite Tutorial:
.h
#import <Foundation/Foundation.h>
#import <sqlite3.h>
@interface FailedBankDatabase : NSObject {
sqlite3 *_database;
}
+ (FailedBankDatabase*)database;
- (NSArray *)failedBankInfos;
@end
.m
#import "FailedBankDatabase.h"
#import "FailedBankInfo.h"
@implementation FailedBankDatabase
static FailedBankDatabase *_database;
+ (FailedBankDatabase*)database {
if (_database == nil) {
_database = [[FailedBankDatabase alloc] init];
}
return _database;
}
Please correct where I am wrong:
The sqlite3 * database
:
- Isn't a property
- Doesn't have any synthesize
- Doesn't have any setter or getter in .m file so no other class can access it--defeating the purpose of placing in
.h
file
All meaning we can't access nor set it! Why are we doing this?
What what is the purpose of placing this in .h
file; Why not just
write as a property? Or just write in our .m
file alone?
Edit: What is the modern way of using Sqlite3 in Objective-C?
回答1:
It was not always possible to declare instance variables in the implementation
block. It has been possible for several years, but the date of that tutorial is April 8, 2010. When it was written, the author probably wanted it to work on older versions of the compiler.
Because _database
is not declared @private
, it is in fact possible to access the instance variable outside of the FailedBankDatabase
implementation. In Objective-C, you can treat an object pointer as a struct pointer and access its instance variables like struct fields. So you could do this:
#import "FailedBankDatabase.h"
int main(int argc, char *argv[])
{
FailedBankDatabase *db = [FailedBankDatabase database];
printf("instance variable: %p\n", db->_database);
return 0;
}
That's probably a bad idea, though.
UPDATE
Since your sqlite3 *_database
is intended to be private, you probably just want to do this:
FailedBankDatabase.h
#import <Foundation/Foundation.h>
@class FailedBankInfo;
@interface FailedBankDatabase : NSObject
+ (FailedBankDatabase*)database;
- (NSArray<FailedBankInfo *> *)failedBankInfos;
@end
FailedBankDatabase.m
#import "FailedBankDatabase.h"
#import "FailedBankInfo.h"
#import <sqlite3.h>
@implementation FailedBankDatabase {
sqlite3 *_database;
}
static FailedBankDatabase *theInstance;
+ (FailedBankDatabase*)database {
if (theInstance == nil) {
theInstance = [[FailedBankDatabase alloc] init];
}
return theInstance;
}
回答2:
You're part right, sqlite3 *_database
isn't a property, has no synthesised setter or getter, but you can access it - by direct reference. If it's in the header it's publicly declared so anyone with an instance of FailedBankDatabase
can directly access the memory location of _database
and interact with it. It just doesn't call a getter to do it.
Because of this using properties is better. By asking clients to go through the getter you have more control over access.
This static FailedBankDatabase *_database;
is a same name but completely unrelated variable. It's static so it has class scope and the scope of the method which is accessing _database
determines which variable is being accessed. This is confusing and bad form...
来源:https://stackoverflow.com/questions/36576705/what-is-the-use-of-placing-an-instance-variable-in-h-where-it-wouldnt-have-a-g