任何人都可以解释Objective-C中协议和类别之间的差异吗?你什么时候用另一个?
我有一个Objective-C协议,我试图在Swift类中实现.例如:
@class AnObjcClass;
@protocol ObjcProtocol <NSObject>
- (void)somethingWithAnArgument:(AnObjcClass *)arg;
@end
Run Code Online (Sandbox Code Playgroud)
当我尝试在这样的Swift类中符合它时:
@objc class SwiftClass: NSObject, ObjcProtocol {
// ...
}
Run Code Online (Sandbox Code Playgroud)
我得到以下可怕的编译器错误:
类型"SwiftClass"不符合协议"ObjcProtocol",因为它具有无法满足的要求.
我该如何解决这个问题?
objective-c objective-c-protocol swift objective-c-swift-bridge
我最近一直在学习Swift.
我决定编写一个混合的Swift/Objective-C应用程序,它使用两种语言实现的相同算法完成计算密集型任务.
该程序计算大量素数.
我定义了一个协议,Swift和Objective-C版本的计算对象都应该符合.
对象都是单例,所以我在Objective-C中创建了一个典型的单例访问方法:
+ (NSObject <CalcPrimesProtocol> *) sharedInstance;
Run Code Online (Sandbox Code Playgroud)
整个协议看起来像这样:
#import <Foundation/Foundation.h>
@class ComputeRecord;
typedef void (^updateDisplayBlock)(void);
typedef void (^calcPrimesCompletionBlock)(void);
@protocol CalcPrimesProtocol <NSObject>
- (void) calcPrimesWithComputeRecord: (ComputeRecord *) aComputeRecord
withUpdateDisplayBlock: (updateDisplayBlock) theUpdateDisplayBlock
andCompletionBlock: (calcPrimesCompletionBlock) theCalcPrimesCompletionBlock;
@optional //Without this @optional line, the build fails.
+ (NSObject <CalcPrimesProtocol> *) sharedInstance;
@end
Run Code Online (Sandbox Code Playgroud)
该类的Objective-C版本完全按照上面的定义实现方法,不用担心.
swift版本有一个方法:
class func sharedInstance() -> CalcPrimesProtocol
Run Code Online (Sandbox Code Playgroud)
但是,如果我使该方法成为协议的必需方法,我得到编译器错误"类型"CalcPrimesSwift不符合协议'CalcPrimesProtocol'.
但是,如果我在协议中将单例类方法sharedInstance标记为可选,那么它可以工作,我可以在我的Swift类或Objective-C类上调用该方法.
我是否错过了Swift类方法定义中的一些细微之处?考虑到我可以在我的Swift类或Objective-C类上调用sharedInstance()类方法,这似乎不太可能.
您可以从Github下载该项目,如果您愿意,可以查看它.它叫做SwiftPerformanceBenchmark.(链接)
interop objective-c objective-c-protocol swift objective-c-nullability
有一种-[NSObject conformsToProtocol:]方法可以检查是否采用了特定的协议.是否有任何方法可以获取类的所有采用的协议,而不是检查列表?
introspection objective-c objective-c-runtime objective-c-protocol
Objective-C协议可以是通用的吗?
按照本教程,我基本上是在寻找类似的东西:
@protocol ItemsStore<__covariant ObjectType> <NSObject>
-(NSArray <ObjectType> *)items;
@end
Run Code Online (Sandbox Code Playgroud)
对于某些ObjectType"实现"("继承")另一种协议的人来说,这是一种通用协议NSObject
我可以使用类别扩展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) 我已经读过你应该尝试@class在头文件中使用而#import不是当你@class包含你正在尝试使用的委托协议时这不起作用.
MyView.h
#import <UIKit/UIKit.h>
@class MyCustomClass; // <-- doesn't work for MyCustomClassDelegate, used below
@interface MyView : UIView <MyCustomClassDelegate>
@end
Run Code Online (Sandbox Code Playgroud)
我想我忽视了一些事情,有没有办法@class在这种情况下工作或者是#import我唯一的选择?
编辑:当然,解决这个问题的方法是在.m文件的私有接口部分而不是.h文件中声明#import MyCustomClass和MyCustomClassDelegate.
import objective-c header-files forward-declaration objective-c-protocol
我习惯于看到类似的东西,id<NSCopying> myVar或者MyObject<NSCopying> myVar我们在说明有问题的变量可以很高兴地拥有NSCopying调用它的方法,而编译器不会摇摆不定.
但是我最近发现了一些定义了这样一个变量的代码:
Class<NSCopying> myClass;
Run Code Online (Sandbox Code Playgroud)
我想知道这实际意味着什么,因为它似乎与前两个例子略有不同.似乎我们说变量myClass可以愉快地接受来自的方法调用NSCopying- 但是具有能够接受这些实例变量方法的类类型似乎没有多大意义.
在我看来,类型的变量在技术上是对象本身,这可能让我或编译器(可能是我!)感到困惑.
所以我猜我在问:
Class<NSCopying> myClass;实际上是什么意思Class<NSCopying> myClass;有所不同id<NSCopying> myVarClass<NSCopying> myClass;有意义地使用?笔记:
NSCopying作为一个例子,并不是我用例的组成部分Class我指的是Class用于声明类型变量的Obj-C关键字Class.我不是将它用作任何类类型的通用术语.为什么我要使用协议而不是创建子类并继承方法..?
请向我解释一下,我对这个话题感到困惑,我对阅读本书中的解释并不十分满意.
我在哪里使用协议而不是其他方式来获取方法..?如果我可以继承类并获取方法,为什么我要使用我需要定义方法的协议?
我试图枚举一堆对象,根据情况,这些对象可能是 NSArray 或 NSOrderedSet。由于两者都符合 NSFastEnumeration,我希望它能工作:
id<NSFastEnumeration> enumerableSet =
(test) ?
[NSArray arrayWithObjects:@"one", @"two", @"three", nil] :
[NSOrderedSet orderedSetWithObjects:@"one", @"two", @"three", nil];
NSEnumerator *e = [enumerableSet objectEnumerator];
Run Code Online (Sandbox Code Playgroud)
但是,我收到以下编译器错误:
选择器“objectEnumerator”没有已知的实例方法。
我怀疑这里有一些语法错误,我之前没有太多使用 id 构造。我可以将其中一个或两个集合转换为公共类,但如果可能的话,我想更好地了解这里发生的情况。
有没有办法做这样的事情(下面不起作用):
@protocol ElementPicker <UIViewController>
- (id)initWithFile:(NSFileWrapper *)file andInfo:(NSString *)info;
@property (nonatomic, weak) NSObject<ElementPickerDelegate> *delegate;
@end
Run Code Online (Sandbox Code Playgroud)
那么实现"ElementPicker"的对象必须继承UIViewController?
我有一个条件,我希望视图控制器符合4种协议中的任何一种.
有没有办法检查它是否符合这4个协议中的任何一个而不在我的if中做一堆或语句?
你能制作一系列协议吗?
我正在尝试创建一个访问我的web api的通用存储库(模式).我无法理解协议如何在objective-c中工作(我来自c#,其中接口有点不同).
我想要做的是让ProtocolA成为另一个ProtocolB中的参数,然后是ProtocolA上ProtocolB访问方法的实现,因为传入ProtocolB的对象必须实现ProtocolA本身.我正确地考虑了吗?
这就是我到目前为止所做的,但似乎无法让它发挥作用 - 也许我的逻辑错了:
//PGenericModel.h
@protocol PGenericModel <NSObject>
- (void)testMethod;
@end
Run Code Online (Sandbox Code Playgroud)
//PGenericRepository.h
#import "PGenericModel.h"
@protocol PGenericRepository <NSObject>
@required
- (void)Get:(id<PGenericModel>*)entity;
@end
Run Code Online (Sandbox Code Playgroud)
//GenericRepository.m
#import "GenericRepository.h"
@implementation GenericRepository
- (void)Get:(id<PGenericModel>*)entity
{
//GET
[entity testMethod] <-- this doesn't work...
}
@end
Run Code Online (Sandbox Code Playgroud) objective-c ×13
ios ×2
swift ×2
class ×1
generics ×1
header-files ×1
import ×1
interop ×1
nsenumerator ×1