How does swift know which files to import? - ios

I'm diving into swift from the land of Objective-C, and I'm curious about swift's importing functionality. I've discovered that there's no need to import my own classes, like so:
Objective-C:
#import <UIKit/UIKit.h>
#import "CustomObject.h"
CustomObject* newObject = ...
Swift:
import UIKit
//no need to import CustomObject
var newObject: CustomObject...
My question is, how does swift accomplish this? Where does it look for .swift files to automatically import? Is it just any .swift file that's added to your project's target? I don't want to just handwave this and then get caught by surprise later when something doesn't import like magic!

I'm not sure I'm going to explain this with grace but here it goes...
Let's say you're creating an app called Battlefront. When you're adding files/classes to your application, they are in fact added to your app's module, the Battlefront module. Let's say you created a class called Hero, well, your class is not only Hero, it is Battlefront.Hero but since you're using it in the context of the Battlefront module, there is no need to specify the module name when using your class.
Imports in Swift works mostly with modules. I suppose you could import a single class in Swift but I haven't tried it so I can't comment on this. Let's say you're importing CoreData, well you're importing the whole module by using import CoreData.
By default, classes are using the internal access control. If you wanted to expose classes inside Battlefront to be available to other modules, you'd have to specify your class as public:
// Default is internal, not available outside Battlefront
class Hero {
}
// Public class, is available outside Battlefront
public class Weapon {
}
You can read more on Access Control here.
I suppose you could simplify the relationship to Target equals a Module but that would be taking a shortcut. Could be a start of understanding the concept though.

Short answer: yes, Xcode accesses all .swift files in your project.

Related

Any way to use a plain Swift class in Objective C files?

This question isn't about bridging headers and all that. I've got all that working. My question is specifically about what I need to do to my Swift classes to get them to show up in Obj-C code.
Take, for example, this simple class:
class MyClass {
var value: String = ""
}
If I have this class in my Project, it doesn't get included in the MyProject-Swift.h file that gets auto-generated. My understanding is that in order to use a Swift class in Objective-C, my class needs to derive from a class that Objective-C knows about. This is where I start to doubt the actual requirements.
If my class were derived from a UIViewController, then no problem. But if this is just a model object, then it's not deriving from anything. While it is entirely possible to easily make my class derive from NSObject, and thus, it gets properly imported into the Obj-C code, deriving from NSObject can cause other issues down the road.
So if I don't want to make my class derive from NSObject, what can I do to make it visible to my Obj-C files? Is there a doc I just couldn't find that explains how to do this?
As far as I am aware currently, Only Swift classes that inherit from NSObject can be declared #objc and bridged into an Objective-C project.
Without that conformance/inheritance, you'll end up missing some crucial functionality to Objective-C like message sending.
All of that being said, an Objective-C class has to inherit from a parent class and the default root class is NSObject. You almost definitely want to just inherit and make your class a PONSO.

Short-circuit when using a Swift protocol

As known, it is not possible to include the interface header file from a file in the -Header.h.
My actual problem is that I have the definition of a class one protocol of which is a Swift one:
#protocol arrivingDelegate;
#interface palettaTraffic : NSObject<MKMapViewDelegate, arrivingDelegate> {
}
If I import the *-Swift.h file I get into the ugly cycle when the file is included in another one that is included in the header file.
This is what happens when I use the #protocol directive: it is a warning, but quite a disturbing one.
This is how the swift protocol is defined:
#objc public protocol arrivingDelegate {
func submitManualBusLine(busStripe:StripeProtocol)
}
I also found a similar post:
Swift protocol in Objective-C class
But none of the suggestions seem to apply.
If I import the *-Swift.h file I get into the ugly cycle when the file is included in another one that is included in the header file.
Okay, but that is what you have to do. I don't see you doing it the screen shot above, which is why your protocol is not being seen.
The solution to the "ugly cycle" should be just a matter of tweaking the order in which things are imported in your various Objective-C files.
Adopting swift protocols in Objective-c is a tricky process. I fixed the issue by porting the adopting class to Swift too.
What I tend to do in my projects is putting the protocol conformance of the ObjC class in a Swift file, to avoid this error. Usually the file where the protocol is defined.
extension PalettaTraffic: ArrivingDelegate {}
Why? We're migrating our codebase from ObjC to Swift, but we cannot migrate every class at the same time. Because of this we have a large 'seem' between Swift & ObjC where Swift types need ObjC and vice versa. For me, this is the solution that causes the least amount of work right away.

Swift build error (involving word "class" as argument) with subclassed Objective-C class

I have a build error when trying to subclass a custom Objective-C class (a subclass of UIViewController) in Swift.
When I try to subclass in Swift, I get the build errors in the picture below. All of them relate to the use of the word class as an argument in the OCMapper library (where I've opened an issue as well).
Some more notes:
In the project, I both import and use Objective-C code in the Swift code and import and use Swift code in the Objective-C code.
I import the compiled Module-Swift.h only in .m and .mm files and forward declare classes that I need in .h files.
I've attempted to create a Module-Swift-Fixed.h class where I forward declare and/or import the custom Objective-C class headers (as recommended here), but that hasn't made a difference.
Has anyone seen anything like this before or have a solution?
I have as yet not been able to trace where in the language spec this is documented, but I suspect you have come across the same problem that I recently faced in objective-c since moving to Xcode 6.4.
I had a message (method) defined as follows
- (BOOL)canProcessClass:(Class) class {
return [class isSubclassOfClass:[NSSet class]];
}
with the same compile error as you mentioned Expected identifier. The fix was simple - just rename the the class argument to something like classToProcess. Which would give you the following
- (BOOL)canProcessClass:(Class) classToProcess {
return [classToProcess isSubclassOfClass:[NSSet classToProcess]];
}
Hence just rename the arguments in your Swift code to not use the (key)word class and you should be fine.
If anyone can point me to the language spec that documents this I would really appreciate it. As far as I'm aware you shouldn't use Class, but I haven't able to find anything about class except the obvious that it is a message (method) available on classes.

Swift - Shared Core Data in Framework - auto-generated classes aren't public?

I'm playing around with sharing a Core Data model in an App Group for a WatchKit app in Swift, loosely following/mimicing this guy's work. I've created a custom framework (called CoreDataKit) and put the .xcdatamodeld file to be a member only of the framework target; I've created a CoreDataStack object which creates and manages the core data stack, which is also a member only of the framework target. Finally, I've created a new entity in the data model, and then used Xcode to auto generate the Swift file for that entity, which gives a class structure that looks like:
import Foundation
import CoreData
class FlightStatus: NSManagedObject {
#NSManaged var altitude: NSNumber
}
When I import CoreDataKit into my view controller in the iOS app to start doing Core Data stuff, I'm able to access the CoreDataStack, but not the FlightStatus class - I get a Use of undeclared type 'FlightStatus' error.
When I go into the FlightStatus.swift file and make it a public class, however, the error goes away. But this makes me a little uncomfortable - I've been trained never to touch the auto-generated Core Data classes, because they may need to be regenerated at any time, and therefore I tend to add helper methods and the like in categories on the auto-generated Core Data classes.
Similarly, I can't access the altitude variable unless I make it public.
Am I going wrong somewhere? Is there a way I can ensure that my auto-generated Core Data entity classes can be visible when the framework is imported without having to manually add the public keyword to them?
Make sure to add #objc(CoreDataClassName) in your class declaration. Modifying your original code slightly:
import Foundation
import CoreData
#objc(FlightStatus) class FlightStatus: NSManagedObject {
#NSManaged var altitude: NSNumber
}
EDIT: I just saw that you mentioned in the comments of your original post that doing this didn't help. Did you follow the above format exactly? Also, regarding your intuition that you shouldn't mess with the CD auto generated files -- Apple is clearly still working out some of the kinks with Swift's Core Data integration, so unfortunately a bit of tinkering is often required. (Another example: Core Data doesn't autogenerate any support for optionals at the moment.)

Subclassing UIGestureRecognizer with Swift and Xcode 6 - how do I import UIGestureRecognizerSubclass.h?

You can't write to self.state in the subclass unless you import UIGestureRecognizerSubclass.h as indicated here.
In a Swift environment, I'm confused how I'd go about importing this. I tried import UIGestureRecognizerSubclass.h, and without the .h, but I still can't write to self.state.
How would I accomplish this?
The Swift equivalent is simply:
import UIKit.UIGestureRecognizerSubclass
That imports the appropriate header.
You need to have or create a -Bridging-Header.h file to import objc headers such as the one you want. The import line looks like this:
#import <UIKit/UIGestureRecognizerSubclass.h>
If you don't already have a bridge header file in your app, the easiest way to get one is to add an objc class to your project, and xcode will ask if you want one, then creates the file and ties it into the settings for you. You can then delete the objc class.
Everything in that header file is automatically made available to your Swift code, no need to add any import lines in your swift files.

Resources