Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 这是一个好的(类似可可豆,苹果批准)模型类吗?_Objective C_Cocoa_Models_Cocoa Design Patterns - Fatal编程技术网

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

我使用Objective-C已经有一段时间了,但我并没有很好地遵循苹果的指导方针。最近我读了很多书,我试着做一些简单的事情,但是做得很好

我是否遗漏了任何主要概念?请不要提及
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
}