背景.
请考虑以下步骤:
1)在Xcode中创建一个新的"单视图应用程序".
2)创建一个类别NSObject + Extension.h和.m文件:
// .h
@interface NSObject (Extension)
- (void)someMethod;
@end
// .m
@implementation NSObject (Extension)
- (void)someMethod {
NSLog(@"someMethod was called");
}
@end
Run Code Online (Sandbox Code Playgroud)
3)确保NSObject+Extension.m文件包含在主目标中.
4)将以下行添加到AppDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[NSString new] performSelector:@selector(someMethod)];
return YES;
}
Run Code Online (Sandbox Code Playgroud)
5)确保应用程序中的任何位置都不存在该#import "NSObject+Extension.h行!
6)运行应用程序.
输出是
2013-08-27 04:12:53.642 Experimental[32263:c07] someMethod was called
Run Code Online (Sandbox Code Playgroud)
问题
我想知道在应用程序的任何地方都没有这个类别的#import ,NSString 如何仍然可以使用NSObject + Extension?这种行为让我对我声明的每个Objective-C类别感觉非常糟糕,因为我希望我声明的类别仅在它们声明的范围内可用.例如,我希望NSObject Extension仅在某个类中扩展,但不能在整个应用程序中扩展,因为否则其全局空间会变为"污染".
有没有办法避免这种行为?我确实希望我的类别仅在我明确导入它们时才能工作,而不是在我将它们链接到我用来运行的目标时.
我刚刚开始创建自己的框架重新组合一些有用的帮助器,工具,工具等.一切正常,我只是想知道是否可以直接在我的主头文件框架文件中导入我的类别.
例如,我的框架名为myFramework.我在公共标题中放了一个类名myFramework.h,我写了所有的导入:
#import "MyCategory+Helper.h"
#import "MyOtherCategory+Helper.h"
#import "AClass.h"
...
Run Code Online (Sandbox Code Playgroud)
Then I build my framework and distribute it to my team developers.
What I expect is that other developers just have to import to access of all of my framework's categories. It's ok when I subclass instead of using categories but it isn't what I expect.
For the while, I use LoadableCategory.h to make my categories work in my framework and specify to my developers that they should use -ObjC flag …
我有一个类型的类结构UIViewControllerSubclass : UIViewController,其中UIViewControllerSubclass的唯一功能是#import UIViewController+Category.h.我在一个类别中添加方法的原因是我也可以制作UITableViewControllerSubclass : UITableViewController,这#import UIViewController+Category.h也是.众所周知,不要重复自己.
现在假设UIViewController + Category.h具有以下结构:
@interface UIViewController(Category)
- (void) method1;
- (void) method2;
@end
Run Code Online (Sandbox Code Playgroud)
如何安全是它来创建UIViewControllerSubclassSubclass : UIViewControllerSubclass,这将覆盖method1?我认为这会因为Objective-C的消息传递而起作用,但出于某种原因,我的直觉告诉我,我做错了.
我一直在寻找一种方法来使用可选的协议方法并拥有干净的代码.换句话说:
1:respondsToSelector:我的代码没有调用
2.应该适用于任何方法签名,因此NSObject上的类别方法进行检查和调用performSelector:(NSInvocation与ARC合作有问题)
3:此解决方案,IMO,假装是普遍的但具有1的所有缺点
我最终提出了这个想法:
@protocol MyProtocol <NSObject>
@optional
-(void)optionalMethod;
@end
@interface ClassA : NSObject <MyProtocol>
@end
@implementation ClassA
-(void)optionalMethod{
NSLog(@"ClassA implements optionalMethod");
}
@end
@interface ClassB : NSObject <MyProtocol>
@end
@implementation ClassB
//classB does not implement optionalMethod
@end
@interface NSObject (DefaultMyProtocolImplementation)
-(void)optionalMethod;
@end
@implementation NSObject (DefaultMyProtocolImplementation)
-(void)optionalMethod{
NSLog(@"%@ does not implement optionalMethod", NSStringFromClass([self class]));
}
@end
Run Code Online (Sandbox Code Playgroud)
它似乎工作,即:
...
ClassA *objA = [[ClassA alloc] init];
ClassB *objB = [[ClassB alloc] init];
[objA optionalMethod]; //prints …Run Code Online (Sandbox Code Playgroud) protocols objective-c objective-c-runtime ios objective-c-category
我正在创建一个超过NSDate的类别.它有一些实用方法,不应该是公共接口的一部分.
我怎样才能让它们变成私密的?
在类中创建私有方法时,我倾向于使用"匿名类别"技巧:
@interface Foo()
@property(readwrite, copy) NSString *bar;
- (void) superSecretInternalSaucing;
@end
@implementation Foo
@synthesize bar;
.... must implement the two methods or compiler will warn ....
@end
Run Code Online (Sandbox Code Playgroud)
但它似乎不适用于另一个类别:
@interface NSDate_Comparing() // This won't work at all
@end
@implementation NSDate (NSDate_Comparing)
@end
Run Code Online (Sandbox Code Playgroud)
在类别中使用私有方法的最佳方法是什么?
这是此queston的扩展: 是否可以在Objective-C中创建"块"对象的类别.
基本上虽然似乎可以通过NSObject或NSBlock在块上创建类别,但我无法理解块如何能够自我评估.在上一个问题的答案中给出的例子:
- (void) doFoo {
//do something awesome with self, a block
//however, you can't do "self()".
//You'll have to cast it to a block-type variable and use that
}
Run Code Online (Sandbox Code Playgroud)
意味着有可能以某种方式将self转换为块变量,但是如何执行块本身呢?例如,假设我在NSBlock上做了一个类别,并且在一个方法中做了:
NSBlock* selfAsBlock = (NSBlock*)self;
Run Code Online (Sandbox Code Playgroud)
是否有任何消息可以发送给selfAsBlock以对块进行评估?
因为我们知道,我们可以添加使用类别和运行方法,如在Objective-C的变量
objc_setAssociatedObject和objc_getAssociatedObject.例如:
#import <objc/runtime.h>
@interface Person (EmailAddress)
@property (nonatomic, readwrite, copy) NSString *emailAddress;
@end
@implementation Person (EmailAddress)
static char emailAddressKey;
- (NSString *)emailAddress {
return objc_getAssociatedObject(self,
&emailAddressKey);
}
- (void)setEmailAddress:(NSString *)emailAddress {
objc_setAssociatedObject(self,
&emailAddressKey,
emailAddress,
OBJC_ASSOCIATION_COPY);
}
@end
Run Code Online (Sandbox Code Playgroud)
但有人知道做什么objc_getAssociatedObject或objc_setAssociatedObject做什么?我的意思是,我们添加到对象(这里self)的变量存储在哪里?和变量之间的关系self?
我可以使用类别扩展UIView,但是它只适用于实现特定协议(WritableView)的子类吗?
即我可以做以下的事情吗?
@interface UIView<WritableView> (foo) // SYNTAX ERROR
- (void)setTextToDomainOfUrl:(NSString *)text;
- (void)setTextToIntegerValue:(NSInteger)value;
- (void)setCapitalizedText:(NSString *)text;
@end
@implementation UIView<WritableView> (foo)
// implementation of 3 above methods would go here
@end
Run Code Online (Sandbox Code Playgroud)
想象一下,我想将以下类别函数添加到任何实例UILabel:
[label setTextToDomainOfUrl:@"http://google.com"];
Run Code Online (Sandbox Code Playgroud)
这只是设置UILabel的text属性google.com.
同样地,我希望能够在其他几个类上调用此函数:
[button setTextToDomainOfUrl:@"http://apple.com"]; // same as: [button setTitle:@"apple.com" forState:UIControlStateNormal];
[textField setTextToDomainOfUrl:@"http://example.com"]; // same as: textField.text = @"example.com"
[tableViewCell setTextToDomainOfUrl:@"http://stackoverflow.com"]; // same as: tableViewCell.textLabel.text = @"stackoverflow.com"
Run Code Online (Sandbox Code Playgroud)
假设到目前为止我对我的设计非常满意,并且我希望为所有4个类增加2个方法:
[label setTextToIntegerValue:5] // same as: label.text = [NSString stringWithFormat:@"%d", 5]; …Run Code Online (Sandbox Code Playgroud) 我在Xcode 5上安装了带有CocoaPods的AFNetworking 2.1.0.
//ViewController.h
#import <AFNetworking/AFNetworking.h>
#import <AFNetworking/UIImageView+AFNetworking.h>
Run Code Online (Sandbox Code Playgroud)
在UIImageview上调用setImageWithURLRequest,应用程序失败并显示以下日志:
这是错误日志:
2014-02-07 11:55:19.984 OPS[1717:60b] *** Terminating app
due to uncaught exception'NSInvalidArgumentException',
reason: '-[UIImageViewsetImageWithURLRequest:placeholderImage:success:failure:]:
unrecognized selector sent to instance 0x147b06d0'
Run Code Online (Sandbox Code Playgroud)
我已经找到了关于这个问题的一些讨论,但提供的解决方案(添加-ObjC -all_load)在我的情况下不起作用.
任何的想法?
谢谢
我已经为UIColor添加了一些扩展,用于我在整个应用中使用的一些颜色.这是一个例子:
extension UIColor {
func appLightGrayColor() -> UIColor {
return UIColor(red: 190.0/255.0, green: 190.0/255.0, blue: 190.0/255.0, alpha: 1.0)
}
func grayScaleColor(grayScale : CGFloat) -> UIColor {
return UIColor(red: grayScale/255.0, green: grayScale/255.0, blue: grayScale/255.0, alpha: 1.0)
}
}
Run Code Online (Sandbox Code Playgroud)
但是,当我尝试调用它时,我能够无错误地编译的唯一方法是:
UINavigationBar.appearance().barTintColor = UIColor.appLightGrayColor(UIColor())()
Run Code Online (Sandbox Code Playgroud)
这是我通过自动完成得到的:

我究竟做错了什么?
objective-c ×8
ios ×5
afnetworking ×1
cocoa ×1
cocoapods ×1
protocols ×1
swift ×1
xcode5 ×1
xcode6 ×1