Objective c 这是一个好的(类似可可豆,苹果批准)模型类吗?
我使用Objective-C已经有一段时间了,但我并没有很好地遵循苹果的指导方针。最近我读了很多书,我试着做一些简单的事情,但是做得很好 我是否遗漏了任何主要概念?请不要提及Objective c 这是一个好的(类似可可豆,苹果批准)模型类吗?,objective-c,cocoa,models,cocoa-design-patterns,Objective C,Cocoa,Models,Cocoa Design Patterns,我使用Objective-C已经有一段时间了,但我并没有很好地遵循苹果的指导方针。最近我读了很多书,我试着做一些简单的事情,但是做得很好 我是否遗漏了任何主要概念?请不要提及self=[super init];这已经被报道过很多次了。尽管如此,请随意评论我的#pragma marks #import "IRTileset.h" #import "IRTileTemplate.h" @interface IRTileset () //No longer lists protocols becau
self=[super init]
;这已经被报道过很多次了。尽管如此,请随意评论我的#pragma mark
s
#import "IRTileset.h"
#import "IRTileTemplate.h"
@interface IRTileset () //No longer lists protocols because of Felixyz
@property (retain) NSMutableArray* tileTemplates; //Added because of TechZen
@end
#pragma mark -
@implementation IRTileset
#pragma mark -
#pragma mark Initialization
- (IRTileset*)init
{
if (![super init])
{
return nil;
}
tileTemplates = [NSMutableArray new];
return self;
}
- (void)dealloc
{
[tileTemplates release];
[uniqueID release]; //Added because of Felixyz (and because OOPS. Gosh.)
[super dealloc]; //Moved from beginning to end because of Abizern
}
#pragma mark -
#pragma mark Copying/Archiving
- (IRTileset*)copyWithZone:(NSZone*)zone
{
IRTileset* copy = [IRTileset new];
[copy setTileTemplates:tileTemplates]; //No longer insertTileTemplates: because of Peter Hosey
[copy setUniqueID:uniqueID];
return copy; //No longer [copy autorelease] because of Jared P
}
- (void)encodeWithCoder:(NSCoder*)encoder
{
[encoder encodeObject:uniqueID forKey:@"uniqueID"];
[encoder encodeObject:tileTemplates forKey:@"tileTemplates"];
}
- (IRTileset*)initWithCoder:(NSCoder*)decoder
{
[self init];
[self setUniqueID:[decoder decodeObjectForKey:@"uniqueID"]];
[self setTileTemplates:[decoder decodeObjectForKey:@"tileTemplates"]]; //No longer insertTileTemplates: because of Peter Hosey
return self;
}
#pragma mark -
#pragma mark Public Accessors
@synthesize uniqueID;
@synthesize tileTemplates;
- (NSUInteger)countOfTileTemplates
{
return [tileTemplates count];
}
- (void)insertTileTemplates:(NSArray*)someTileTemplates atIndexes:(NSIndexSet*)indexes
{
[tileTemplates insertObjects:someTileTemplates atIndexes:indexes];
}
- (void)removeTileTemplatesAtIndexes:(NSIndexSet*)indexes
{
[tileTemplates removeObjectsAtIndexes:indexes];
}
//These are for later.
#pragma mark -
#pragma mark Private Accessors
#pragma mark -
#pragma mark Other
@end
(编辑:到目前为止,我已经做出了建议的更改,并评论了哪些答案会讨论这些更改,以防有人需要知道原因。)两个小细节:
一个是init方法(风格上我反对有两个不同的返回点,但那只是我),但是没有什么可以阻止super的init返回一个不同的对象,而不是它本身或nil,例如它的类中的不同对象,甚至只是另一个对象。出于这个原因,self=[super init]
通常是一个好主意,即使它在实践中可能不会起多大作用。
第二种是在copyWithZone方法中,不复制tileTemplates,这可能是有意的,但通常是个坏主意(除非它们是不可变的)。复制一个对象应该具有与分配一个新对象相同的效果,例如保留计数1,所以不要自动释放它。而且,看起来你并没有对这个区域做任何事情,所以你应该用类似的东西来代替它
- (IRTileTemplate*)copyWithZone:(NSZone*)zone {
IRTileset* copy = [[IRTileset allocWithZone:zone] init];
[copy insertTileTemplates:[tileTemplates copyWithZone:zone]
atIndexes:[NSIndexSet indexSetWithIndex:0]];
[copy setUniqueID:uniqueID];
return copy;
}
这就是我发现的一切;除了保留拷贝数(这将导致以后的bug)之外,大部分都是我喜欢的东西,如果你更喜欢的话,你可以自己做。干得好看起来不错,只是你的属性被外部对象任意操纵了。理想情况下,数据应仅由模型类本身直接操作,外部对象应仅通过专用方法访问 例如,如果某些外部代码调用此函数,该怎么办:
myIRTileset.tileTemplates=someArray;
砰,你丢失了所有的数据
您应该将这两个数据属性都定义为只读。然后在类内部写入访问器,该类将在类实现中管理它们的保留。这样,外部对象更改tileTemplates的唯一方法是调用-insertTileTemplates:atIndexes:
和removetiletemplatesatinexes:
方法
Edit01:
我想我一开始就弄坏了,让我再试一次。您应该按照以下模式设置数据模型类:
接口
@interface PrivateTest : NSObject {
@private
//iVar is invisible outside the class, even its subclasses
NSString *privateString;
@public
//iVar is visible and settable to every object.
NSString *publicString;
}
@property(nonatomic, retain) NSString *publicString; //property accessors are visible, settable and getable.
//These methods control logical operations on the private iVar.
- (void) setPrivateToPublic;
- (NSString *) returnPrivateString;
@end
所以在使用中,它看起来像:
实施
#import "PrivateTest.h"
//private class extension category defines
// the propert setters and getters
// internal to the class
@interface PrivateTest ()
@property(nonatomic, retain) NSString *privateString;
@end
@implementation PrivateTest
//normal synthesize directives
@synthesize privateString;
@synthesize publicString;
// Methods that control access to private
- (void) setPrivateToPublic{
//Here we do a contrived validation test
if (self.privateString != nil) {
self.privateString=self.publicString;
}
}
- (NSString *) returnPrivateString{
return self.privateString;
}
@end
您可以这样使用它:
PrivateTest *pt=[[PrivateTest alloc] init];
// If you try to set private directly as in the next line
// the complier throws and error
//pt.privateString=@"Bob"; ==> "object cannot be set - either readonly property or no setter found"
pt.publicString=@"Steve";
[pt setPrivateToPublic];
NSLog(@"private=%@",[pt returnPrivateString]); //==> "Steve"
现在该类具有防弹数据完整性。应用程序中的任何对象都可以设置和获取publicString
string属性,但外部对象无法设置或获取private
这意味着您可以安全地允许应用程序中的任何对象访问实例,而不必担心某个次要对象或方法中的一行粗心的代码会毁掉一切
请不要提及self=[super init]
那你为什么不这么做
initWithCoder:
:您应该使用由[self init]
返回的对象,而不是假设它初始化了初始对象
正如阿比泽恩在评论中所说,[super dealoc]
应该排在最后。否则,您将访问解除分配对象的实例变量
这里的返回类型应该是id
,与NSCopying协议声明的返回类型匹配
在一个索引中插入零个或多个对象。使用以下范围创建索引集:location=0,length=tileTemplates数组的计数。更好的是,只需将以下内容指定给整个属性值:
copy.tileTemplates = self.tileTemplates;
或者直接访问实例变量:
copy->tileTemplates = [tileTemplates copy];
(请注意,当绕过属性访问器时,您必须自己执行复制
,并且您是复制
代表副本复制阵列。)
copyWithZone:
不应返回自动删除的对象。根据,copy或copyWithZone:的调用方拥有副本,这意味着释放副本是调用方的工作,而不是copyWithZone:
您可能还需要实现单对象数组访问器:
- (void) insertObjectInTileTemplates:(IRTileTemplate *)template atIndex:(NSUInteger)idx;
- (void) removeObjectFromTileTemplatesAtIndex:(NSUInteger)idx;
当然,这是可选的
//但是,我应该列出协议吗
在这里,即使他们已经
在IRTileset.h中列出
不,你不应该。实现文件中声明的类扩展名是一个扩展名,因此您不必关心该类声明遵循哪些协议
我建议用下划线标记实例变量的名称:\u tileTemplates
。(纯粹主义者会告诉你在下划线前加上词缀而不是前缀;如果你害怕的话就这样做。)
不要使用new
实例化类。据我所知,这是不被推荐的
[NSMutableArray new]; // :(
[NSMutableArray arrayWithCapacity:20]; // :)
在进行您自己的解除分配之前,不要呼叫[超级解除分配]!在某些情况下,这可能会导致崩溃
- (void)dealloc
{
[tileTemplates release];
[super dealloc]; // Do this last
}
我不确定uniqueID的类型是什么,但它是否也应该在dealloc
中发布
<>我永远不会把我的@合成指令放在文件的中间(把它们直接放在下面的“实现”下面)。< /P>
另外,由于不清楚这个类的角色,
countOfTileTemplates
对我来说也不太好。如果不清楚这个类是如何保存平铺模板的,也许“count”就可以了。对于dealoc
,你应该在自己清理完之后调用[super dealoc]
。你能留下一份原始代码的副本吗,这样我就可以了解回复的内容了?谢谢;)庞蒙:还有,这就是为什么我一直在每一个变化旁边留下评论。这不是为了破坏聚会,但我的理解是,这不是为了像这样的“讨论”,而是为了那些
return [copy autorelease];
}
@synthesize tileTemplates;
[et al]
- (void) insertObjectInTileTemplates:(IRTileTemplate *)template atIndex:(NSUInteger)idx;
- (void) removeObjectFromTileTemplatesAtIndex:(NSUInteger)idx;
[NSMutableArray new]; // :(
[NSMutableArray arrayWithCapacity:20]; // :)
- (void)dealloc
{
[tileTemplates release];
[super dealloc]; // Do this last
}