Ray Wenderlich 所著的“iOS6 by Tutorials”一书中有一个关于编写更多“现代”Objective-C 代码的非常好的章节。在一节中,这些书描述了如何将 iVar 从类的头文件移动到实现文件中。
由于所有 iVar 都应该是私有(private)的,这似乎是正确的做法。
但到目前为止,我发现了 3 种方法。每个人都在做不同的事情。
1.) 将 iVars 放在 @implementantion 下的花括号块中(这就是本书中的做法)。
2.) 将 iVars 放在 @implementantion 下,不带花括号块
3.) 将 iVars 放在 @implementantion 之上的私有(private)接口(interface)中(类扩展)
所有这些解决方案似乎都运行良好,到目前为止我还没有注意到我的应用程序的行为有任何不同。
我想没有“正确”的方法可以做到,但我需要编写一些教程,并且我只想为我的代码选择一种方法。
我应该走哪条路?
编辑:我在这里只谈论 iVars。不是属性。只有对象本身需要的附加变量,不应暴露给外部。
代码示例
1)
#import "Person.h"
@implementation Person
{
int age;
NSString *name;
}
- (id)init
{
self = [super init];
if (self)
{
age = 40;
name = @"Holli";
}
return self;
}
@end
#import "Person.h"
@implementation Person
int age;
NSString *name;
- (id)init
{
self = [super init];
if (self)
{
age = 40;
name = @"Holli";
}
return self;
}
@end
#import "Person.h"
@interface Person()
{
int age;
NSString *name;
}
@end
@implementation Person
- (id)init
{
self = [super init];
if (self)
{
age = 40;
name = @"Holli";
}
return self;
}
@end
最佳答案
将实例变量放入 @implementation 的能力块,或在类扩展中,是“现代 Objective-C 运行时”的一个特性,每个版本的 iOS 和 64 位 Mac OS X 程序都使用它。
如果您想编写 32 位 Mac OS X 应用程序,您必须将您的实例变量放在 @interface 中。声明。不过,您可能不需要支持 32 位版本的应用程序。自 5 年前发布的 10.5 (Leopard) 版本以来,OS X 一直支持 64 位应用程序。
因此,让我们假设您只编写将使用现代运行时的应用程序。你应该把你的ivars放在哪里?
选项 0:在 @interface (不要这样做)
首先,让我们回顾一下为什么我们不想将实例变量放在 @interface 中。声明。
@interface向类的用户公开实现的细节。这可能会导致这些用户(甚至在使用您自己的类时您自己!)依赖他们不应该依赖的实现细节。 (这与我们是否声明 ivars @private 无关。)@interface使编译需要更长的时间,因为每当我们添加、更改或删除 ivar 声明时,我们都必须重新编译每个 .m导入接口(interface)的文件。 @interface 中.我们应该把它们放在哪里?@implementation没有大括号(不要这样做)@implementation Person
int age;
NSString *name;
...
.m 中定义全局变量文件,即使在您的 @implementation 中,如果您需要全局变量 - 例如,因为您希望所有实例共享某些状态,例如缓存。但是你不能使用这个选项来声明 ivars,因为它没有声明 ivars。 (此外,您的实现私有(private)的全局变量通常应声明为 static 以避免污染全局命名空间和链接时错误的风险。)@implementation带牙套(Do It)@implementation 中。块,在大括号中,像这样:@implementation Person {
int age;
NSString *name;
}
@implementation 放在同一个文件中的类扩展名中。 .我们不妨把它们放在 @implementation 中在那种情况下。UICollectionView (一个相当大的类),我们可能会决定将管理可重用 View (单元格和补充 View )队列的代码放在一个单独的源文件中。我们可以通过将这些消息分成一个类别来做到这一点:// UICollectionView.h
@interface UICollectionView : UIScrollView
- (id)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;
@property (nonatomic, retain) UICollectionView *collectionViewLayout;
// etc.
@end
@interface UICollectionView (ReusableViews)
- (void)registerClass:(Class)cellClass forCellWithReuseIdentifier:(NSString *)identifier;
- (void)registerNib:(UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier;
- (void)registerClass:(Class)viewClass forSupplementaryViewOfKind:(NSString *)elementKind withReuseIdentifier:(NSString *)identifier;
- (void)registerNib:(UINib *)nib forSupplementaryViewOfKind:(NSString *)kind withReuseIdentifier:(NSString *)identifier;
- (id)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath*)indexPath;
- (id)dequeueReusableSupplementaryViewOfKind:(NSString*)elementKind withReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath*)indexPath;
@end
UICollectionView UICollectionView.m 中的方法我们可以在 UICollectionView+ReusableViews.m 中实现管理可重用 View 的方法,这使我们的源代码更易于管理。@implementation在 UICollectionView.m ,所以编译器会在 .o 中发出它们文件。我们还需要将这些实例变量暴露给 UICollectionView+ReusableViews.m 中的代码。 ,所以这些方法可以使用 ivars。// UICollectionView_ReusableViewsSupport.h
@interface UICollectionView () {
NSMutableDictionary *registeredCellSources;
NSMutableDictionary *spareCellsByIdentifier;
NSMutableDictionary *registeredSupplementaryViewSources;
NSMutableDictionary *spareSupplementaryViewsByIdentifier;
}
- (void)initReusableViewSupport;
@end
UICollectionView.m并在 UICollectionView+ReusableViews.m ,以便所有需要看到这些 ivars 的东西都能看到它们。我们还抛出了一个我们想要主 init 的方法。调用以初始化可重用 View 管理代码的方法。我们将从 -[UICollectionView initWithFrame:collectionViewLayout:] 调用该方法在 UICollectionView.m ,我们将在 UICollectionView+ReusableViews.m 中实现它.
关于objective-c - 将 iVar 放在 "modern"Objective-C 的何处?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13566862/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou
我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-
为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
我在理解Enumerator.new方法的工作原理时遇到了一些困难。假设文档中的示例:fib=Enumerator.newdo|y|a=b=1loopdoy[1,1,2,3,5,8,13,21,34,55]循环中断条件在哪里,它如何知道循环应该迭代多少次(因为它没有任何明确的中断条件并且看起来像无限循环)? 最佳答案 Enumerator使用Fibers在内部。您的示例等效于:require'fiber'fiber=Fiber.newdoa=b=1loopdoFiber.yieldaa,b=b,a+bendend10.times.m
我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test
我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que
我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file