Swift Classes vs. Objective-C Classes. Am I on the right track? - objective-c

I am new to Swift. I've taken a couple of online course and have started converting an existing Objective-C project to Swift as a learning experience. I have a few questions if someone has time. I've searched the board but haven't found the answers. I am sorry if I missed them.
Delegate Protocols - I'm used to defining my own in Objective-C. Below I have the original Objective-C version and below it I have my new Swift version. Have I followed the correct design pattern for Swift?
I find myself making optionals for all of the properties especially objects like NSData or custom classes. Is this practice acceptable? I am not sure how I would know an initial value for most objects. I know the language wants you to set an initial value but it seems strange for certain objects.
If I am not mistaken we do not have to call self.super init in custom initializers in Swift. Is this correct?
Objective-C Version
#protocol FLOParserHandlerDelegate;
#interface FLOParserHandler: NSObject <NSXMLParserDelegate>
// Properties
#property (nonatomic, strong) NSMutableData *PHData;
#property (nonatomic, strong) NSMutableString *currentParsedCharacterData; // This grabs the characters as they come in and adds them together.
#property (nonatomic, strong) NSMutableArray *XMLDataArray; // This is the master array that holds all of the article arrays with the date, title and link objects.
#property (nonatomic, strong) NSMutableDictionary *dateTitleLinkDictionary;// This is used to gather the date, title and link in an array to added to the master array.
// Delegate Property
#property (nonatomic, weak) id <FLOParserHandlerDelegate> delegate;
// init Methods
- (id) initWithCHData: (NSMutableData *) data;
// Class Methods
-(void) startParser;
#end
#pragma mark-
#pragma mark FLOParserHandler Protocol Definition
#protocol FLOParserHandlerDelegate
#optional
- (void) floParserHandlerDidFinishParsing: (FLOParserHandler *) parserHandler;
- (void) floParserHandler: (FLOParserHandler *) parserHandler didFailWithError: (NSError *) error;
#end
Swift Version
import Foundation
protocol FLOParserHandlerDelegate
{
func floParserHandlerDidFinishParsing(parserHandler : FLOParserHandler) -> ()
func floParserHandler(parserHandler : FLOParserHandler, error : NSError) -> ()
}
// Note that we have to inherit from NSObject here. I believe this iis because we are mixing it with Objective-C.
class FLOParserHandler : NSObject, NSXMLParserDelegate
{
var PHData : NSData?
var currentParsedCharacterData : String?
var XMLDataArray : [String]?
var dateDictionary : [String:NSDate]?
var titleDictionary : [String:String]?
var linkDictionary : [String:String]?
// Delegate Property
var delegate : FLOParserHandlerDelegate?
// Init Methods
init(data : NSData)
{
self.PHData = data
}
// Class Methds
func startParser()
{
var parser = NSXMLParser(data: self.PHData)
parser.delegate = self
parser.parse()
}
}
Thank you,
Jon

Your protocol definition is valid. There is one little thing you should know about:
As with type property requirements, you always prefix type method
requirements with the class keyword when they are defined in a
protocol
protocol SomeProtocol {
class func someTypeMethod()
}
Its perfectly fine to use optionals, or you may use implicity unwrapped optionals like NSData!. In which case you should do this and where no, you may read here: Why create "Implicitly Unwrapped Optionals"?.
Shortly, you doing this in following situations:
a) Constant cannot be defined using initializtion, but you know that it would not be nil (otherwise app will crash)
b) Objective-C Api required you to use pointers, and pointers in Obj-C could be nil. In that case you use imilicity unwrapped optionals.
You always have to call 'super' if you have superclass, to be sure, that class is properly initialized.
Hope that helps.

Related

Access instance properties of an Objective-C NSDocument subclass from Swift plugin?

The goal is to write a Swift plugin which can access public instance properties of an Objective-C NSDocument subclass. The main application is in Objective-C. The plugin is intended to be just Swift.
The main application has a public Objective-C document interface:
#interface ObjcNSDocument : NSDocument
#property (nonatomic, readwrite) NSString *markdown;
#property (nonatomic, readonly) NSString *html;
#end
A reasonable Swift counterpart would seem to be:
public class SwiftNSDocument: NSDocument {
public var markdown: String = ""
public var html: String = ""
}
The following Swift code retrieves the current NSDocument OK. However, the casting fails.
public func doFilter() {
let dc = NSDocumentController.shared()
if let document: NSDocument = dc.currentDocument {
print("document.displayName = \(document.displayName)") // works OK
let markdownSource = document as! SwiftNSDocument // FAIL: cannot cast as
}
}
While I'm asking this is general, my particular test case is to rewrite the macdown-gistit Objective-C plugin as close as possible to pure Swift.
Ideally, the solution would not require including any Objective-C code from the application. What is possible, even if not ideal?
Additional Observation
In the case of a working Objective-C plugin, the Application's NSDocument subclass .h file is not included in the plugin project.
Instead, the Objective-C plugin has only the single relevant property as an NSObject subclass.
#protocol MarkdownSource <NSObject>
#property (readonly) NSString *markdown;
#end
The NSDocument is then downcast as the NSObject subclass in Objective-C:
id<MarkdownSource> markdownSource = (id)document;
NSString *markdown = markdownSource.markdown;
Theoretically, one would think that something similar might work in Swift like
public class MarkdownSource: NSObject {
public var markdown: String = ""
}
where id in Object-C would be a Swift Any. I've tried various downcastings were like such as:
let markdownSource: MarkdownSource = (nsdocument as Any) as MarkdownSource
let markdown: String = markdownSource.markdown
I have not, so far, been able to downcast an NSDocument subclass to any NSObject subclass with just the one desired property in Swift.

Is it safe to ignore compiler warning caused by referring to dispatch_queue_t from Swift?

I have an Objective C class which has the following property:
#property (nonatomic, strong, readonly) dispatch_queue_t couchDispatchQueue;
I have a Swift extension of that class where I reference that property like so:
couchDispatchQueue.async {
When I do that, I get the following compiler warning:
Property type 'OS_dispatch_queue * _Nullable' is incompatible with type 'dispatch_queue_t _Nullable' (aka 'NSObject *') inherited from 'BZCouchDatabase'
I can see why, since my app's generated App-Swift.h file has:
#property (nonatomic, readonly, strong) OS_dispatch_queue * _Nullable couchDispatchQueue;
while dispatch_queue_tis defined as:
typedef NSObject<OS_dispatch_queue> *dispatch_queue_t;
Edit
I've figured out the "further complication" that I was missing in my original description. This property is required by an Objective C protocol which also requires inheritance from NSObject. As soon as I make the Swift class inherit from NSObject and conform to the objective C protocol, I get the warning. The following sample code is enough to set off the warning:
Objective C:
#protocol Thingness
#property (nonatomic, strong, readonly, nullable) dispatch_queue_t couchDispatchQueue;
#end
Swift:
class Thing: NSObject, Thingness {
var couchDispatchQueue: DispatchQueue?
}
My question still is: is it safe for me to just silence this warning? Should I file a radar?
Very well described situation — but I can't reproduce it. When I declare
#property (nonatomic, strong, readonly) dispatch_queue_t couchDispatchQueue;
in an Objective-C class file, the generated header shows me
open var couchDispatchQueue: DispatchQueue! { get }
This is thus seen as a normal Swift 3 DispatchQueue, and my call to couchDispatchQueue.async produces no warning at all.
To be clear, I tried it two ways. I declared the couchDispatchQueue property in the .h file for a Thing class. I imported Thing.h into Swift. I then wrote this code in Swift:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
Thing().couchDispatchQueue.async {}
}
}
extension Thing {
func test() {
self.couchDispatchQueue.async {}
}
}
Neither in the straight instance method call nor in the extension do I see any warning.

Objective c protocol generics

Can Objective-C protocol be generic?
Following this tutorial, I'm basically looking for something like that:
#protocol ItemsStore<__covariant ObjectType> <NSObject>
-(NSArray <ObjectType> *)items;
#end
Which is a generic protocol for some ObjectType that "implements" ("inherits") another protocol NSObject
As #rmaddy suggested, and as referred to this questions, it is NOT possible.
Shame, moving to Swift then...
Maybe you could just redefine it as generic in the interface.
#protocol ItemsStore <NSObject>
- (NSArray *)items;
#end
#interface MyItemsStore<ObjectType> : NSObject <ItemsStore>
- (NSArray <ObjectType> *)items;
#end
This seems an unlikely scenario though. You might be better just defining the type of the items in each subclass. Like what Apple do with NSFetchRequest in their core data model generation.
Probably, this question has exactly the same source problem as mine. Well, the idea of the design is great but doesn't work with ObjC. I also was wondering about that. I thought it could work some way like that:
#protocol Prototype<__covariant OtherProtocolOrClass> <NSObject>
/// Construct an object of the desired class or protocol
#property (nonatomic, nonnull, readonly) <OtherProtocolOrClass> objectFromPrototype;
#end
(I have not tested #protocol Prototype <NSObject,__covariant OtherProtocolOrClass> yet, but think it will fail.)
Another object in my framework (it is a collection) states, it can auto-construct an NSArray<ObjectType>* of an object type, if there is a Prototype that returns instances, like this:
#interface ValueProto : NSObject <Prototype<id<Value>>>
#end
#implementation ValueProto
-(id<Value>)objectFromPrototype {
return [Value new];
}
#end
Im my dreams, the collection was constructed like this:
MyCollection<id<Value>>* const collection = [MyCollection new];
collection.prototype = [ValuesProto new];
And if you then access the collection's property, your array of id<Value> objects is constructed on the fly:
-(NSArray<id<Value>>*)values {
NSArray*const sourceCollection = ...
NSMutableArray<id<Value>>* const result = [NSMutableArray arrayWithCapacity:sourceCollection.count];
for (id o in sourceCollection) {
id<Value> v = self.prototype.objectFromPrototype;
v.content = o;
[result addObject:v];
}
return result;
}
Instead one of my class' objects must be the prototype itself:
-(id)objectFromPrototype {
return [self.class new];
}
That clashes with my so-called 'Injector', which constructs and returns objects by protocols instead of classes.
If any Apple engineer is reading this:
Please, provide protocol covariants for ObjC. It's not yet dead! :-)
Why not use generic abstract class?
#interface AbstractItemStore <__covariant ObjectType> : NSObject
- (NSArray<ObjectType> *)items;
#end
#implementation AbstractItemStore
- (NSArray<id> *)items {
NSParameterAssert("Not implemented!");
return nil;
}
#end

What to use for Objective-C objects instead of structs when using ARC?

ARC forbids Objective-C objects in structs or unions.
Unless you add __unsafe_unretained which means its not managed.
I was wonder what people are using in place of structs now if anything?
Or are you retaining everything manually?
It's very simple - if you want to add an object inside a struct, you are doing it wrong. Whenever you need a struct to hold an obj-c object, convert the struct into an obj-c object.
I would manage different objects in one objc-object like this:
#class MyFirst, MySecond;
#interface MyContainer : NSObject
#property (nonatomic, strong, readonly) MyFirst *firstInst;
#property (nonatomic, strong, readonly) MySecond *secondInst;
// optional: convenience initializer
+ (instancetype)containerWithFirstInst:(MyFirst *)firstInst secondInst:(MySecond *)secondInst;
#end
// required by linker: stub definition for the class declared above
#implementation MyContainer
#end
#interface SomeController : NSObject
- (void)doSomething;
#end
#implementation SomeController
- (void)doSomething {
MyFirst *firstInstance = [[MyFirst alloc] initWithSomeParameters:...];
MySecond *secondInstance = [[MySecond alloc] initWithSomeParameters:...];
MyContainer *container = [MyContainer containerWithFirstInst:firstInstance secondInst:secondInstance];
// use container as a struct (but it's definitely an object that is managed by ARC)
}
#end
Wouldn't it be a lot easier to implement a static class and fake its properties, as shown here?
I answered to it here https://stackoverflow.com/a/28845377/1570826
maybe somebody with the right level could mark this or the other as a duplicate.

Is there any way to add an iVar that's not in the header file (not using LLVM 2.0 or later) in Objective-C?

I recently learned that you can add ivar in a class extension with LLVM2.0. (gcc can't do this)
This is somehow really private iVar because other users don't it's existence since it's not in the header file.
like:
//SomeClass.h
#interface SomeClass : NSObject {
}
#end
//SomeClass.m
#interface SomeClass ()
{
NSString *reallyPrivateString;
}
#end
#implementation SomeClass
#end
But this does rely on the compiler. Is there any other way to declare an ivar that's not in the header file?
The only place to declare instance variables is in the interface or a class extension (which is really an extension of the interface). But you can effectively add instance variables at any time with the modern runtime using the associated object functions.
If you are implementing a library and want to hide your instance variables take a look at what Apple does in the interface for UIWebView. They have an internal webview that does not expose a header file.
#class UIWebViewInternal;
#protocol UIWebViewDelegate;
UIKIT_CLASS_AVAILABLE(2_0) #interface UIWebView : UIView <NSCoding, UIScrollViewDelegate> {
#private
UIWebViewInternal *_internal;
}
If you're just going to be using the ivar internally, and you're using the modern runtime (Snow Leopard 64 bit and iOS 3.0+, I think) then you can just declare properties in a class extension and synthesize them inside the class. No ivars are exposed in your header, no messy id _internal objects, and you get around fragile ivars, too.
// public header
#interface MyClass : NSObject {
// no ivars
}
- (void)someMethod;
#end
// MyClass.m
#interface MyClass ()
#property (nonatomic, retain) NSString *privateString;
#end
#implementation MyClass
#synthesize privateString;
- (void)someMethod {
self.privateString = #"Hello";
NSLog(#"self.privateString = %#", self.privateString);
NSLog(#"privateString (direct variable access) = %#", privateString); // The compiler has synthesized not only the property methods, but also actually created this ivar for you. If you wanted to change the name of the ivar, do #synthesize privateString = m_privateString; or whatever your naming convention is
}
#end
This works with Apple's gcc, in addition to LLVM. (I'm not sure if this works on other platforms, ie not Apple's gcc, but it will certainly work for both iOS and Snow Leopard+).