I need use a function from Objective C in Swift class
-(NSString *)encodeBase64ForData{}
In Objective C I call with this form:
#import "NSData+Base64Additions.h"
[videoPath encodeWrappedBase64ForData]
But in Swift, i can't import this class. How can use this encoder?
Thanks!
First hit on google: http://ios-blog.co.uk/tutorials/quick-tips/base64-decoding-in-ios-7-objective-c-and-ios8-swift/
Basically, you don't need to import the category for NSString. You can use the builtin functionality for base64 strings.
let plainString = "my string to encode"
let plainData = (plainString as NSString).dataUsingEncoding(NSUTF8StringEncoding)
let base64String = plainData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.fromRaw(0)!)
println(base64String) // Something like bXkgc3RyaW5nIHRvIGVuY29kZQ==
You need to use the objective-c bridging header file, and add that import into it. The first time you create an objective c class in a swift project it should prompt you to create, otherwise you have to manually create and set it in your build settings "Objective-C Bridging Header".
More info can be found at:
https://developer.apple.com/library/ios/documentation/swift/conceptual/buildingcocoaapps/MixandMatch.html
Related
I've got an Objective C project and I'm trying to use Swift file in it. I've added swift file and Xcode automatically created Bridging Header. So I could create an object of my swift class in obj-c file and access to its properties. But then I added a new string to my swift file. And I can’t access a new-added property from my objective C file. So I think, I have to update or recreate Bridging Header, haven't I? Can anybody help me?
Did you put #objc in front of your class or property? like:
#objc public class myClass {
#objc var str: String = "str"
}
Suppose I have a connector named Connector.m (written in Objective-C). And I would like to create a new connector written using Swift, named Connector.swift. I would like to access all of the variables and methods from Swift. I have create a bridging-header and write import of the header file of the Connector. But I can't access any of global variables on the Objective-C class.
Connector.m
NSString * const kHTTP_METHOD_GET = #"GET";
Connector.swift
public class Connector: NSObject {
var parentConnector : Connector
override init() {
self.parentConnector = Connector
}
func test() {
print(parentConnector.kHTTP_METHOD_GET) //--> ERROR : Value of type 'Connector' has no member 'kHTTP_METHOD_GET'
}
}
Is it possible to do this? Thanks.
Make sure you have header file like this...
{project-name}-Bridging-Header.h
Add your class file in Bridging-Header.h
#import "Connector.h"
And Put your below code in Connector.h file..Because in Bridging-Header.h will only import header file
NSString * const kHTTP_METHOD_GET = #"GET";
to on top of #interface scope..
Add following line in Connector.h.
extern NSString * const kHTTP_METHOD_GET;
Include Connector.h to your bridging header file.
I believe the methods/variables in Connector.m also need to be public for it to work.
This sounds like a good use-case for the Adapter Pattern. But you should be able to access Objective-C code easily.
Make sure your bridging header file is named like this:
{your-project-name}-Bridging-Header.h
Inside your bridging header add the following:
#import "Connector.m"
Then you have to make sure the compiler knows about your bridging header:
Click your root project > Select your target app > Build Settings
Then scroll down until you see this:
Make sure your bridging header is listed, build and you should have access to your Objective-C code.
When you implement a class MyGreatClass in Swift its fully qualified name will by <MyPackageName>.MyGreatClass. This is different to Objective-C, where the fully qualified name of that same class is MyGreatClass.
Unfortunately this introduces a problem for me. When I am using NSUnarchiver and the archive was written with Objective-C objects I cannot unpack it with Swift-classes(see below for a detailed description).
This means I need to find a way to rename the namespace for my Swift classes. How do I do that?
Any help would be great!
Background: Why can't NSUnarchiver see/load my swift class?
I have implemented a small program to read a file, which was archived with NSArchive.
These are my files:
main.swift:
import Foundation
// parse command line - total path to *.trace file (from Apple's Instruments app)
var traceFilePath = Process.arguments[1]
var traceFile = NSURL(fileURLWithPath: traceFilePath)
var error:NSError?
// check if the file exists
if (traceFile?.checkResourceIsReachableAndReturnError(&error) == false){
// file does not exist or cannot be accessed
println("\(error)")
exit(1)
}
var rawData = NSData(contentsOfURL: traceFile!)
var data = NSUnarchiver(forReadingWithData: rawData!)
var decodedObject: AnyObject? = data?.decodeObject()
XRObjectAllocRun.swift:
import Foundation
class XRObjectAllocRun: NSObject {
// class to be implemented
}
When I now run my application on an Instruments-file I am getting the following error: Terminating app due to uncaught exception 'NSArchiverArchiveInconsistency', reason: '*** class error for 'XRObjectAllocRun': class not loaded'.
This is really strange because when I add the exact same class in an Objective-C file with a bridging header file I have no issues.
trace file reader-Bridging-Header.h: is empty.
XRObjectAllocRun.h:
#import <Foundation/Foundation.h>
#interface XRObjectAllocRun : NSObject
#end
XRObjectAllocRun.m:
#import "XRObjectAllocRun.h"
#implementation XRObjectAllocRun
#end
What am I missing? Why is my Objective-C class found, whereas my Swift class is not?
Swift has no issues for example with var x = XRObjectAllocRun() in main.swift, but yet the NSUnarchiver still complaints about a missing XRObjectAllocRun class when I stay purely within Swift. Is the NSUnarchiver looking in the wrong places - does it for some reason only accept Objective-C classes?
If you want to know what I am trying to do check this stackoverflow question out.
Update
This is what apple writes:
Swift classes are namespaced based on the module they are compiled in, even when used from Objective-C code. Unlike Objective-C, where all classes are part of a global namespace
Further more:
For example, when you create a document–based Mac app, you provide the name of your NSDocument subclass in your app’s Info.plist file. In Swift, you must use the full name of your document subclass, including the module name derived from the name of your app or framework.
Yikes, trying to figure out the mess now...
Try this when you declare your class:
#objc(XRObjectAllocRun) class XRObjectAllocRun: NSObject {
// class to be implemented
}
That will give this class the same name as the archived class, namely XRObjectAllocRun, instead of the namespaced Swift name trace_file_reader.XRObjectAllocRun.
This is always a concern when you're translating from Objective-C to Swift and you've got an existing archive to deal with. See Apple's documentation:
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.html
Note the discussion under "Exposing Swift Interfaces in Objective-C".
I am willing to get a reference to an instance of an Objective-C class by calling, from Swift, one of its class initialiser functions.
The class I am willing to use is AWSMobileAnalytics, available at https://github.com/aws/aws-sdk-ios/blob/master/AWSCore/MobileAnalytics/include/AWSMobileAnalytics.h
It defines a initialiser like this
#interface AWSMobileAnalytics : NSObject
+ (instancetype)mobileAnalyticsForAppId:(NSString *)appId;
...
#end
My code is
let ma = AWSMobileAnalytics.mobileAnalytics(forAppId: appId)
(and I tried many variant of it). The compiler says
Type AWSMobileAnalytics.Type has no member 'mobileAnalytics'
Any suggestion ?
Seb
Make sure you have imported the framework in bridging header.You need to call like this
let ma = ViewController.mobileAnalyticsForAppId("abc")
There's no need to use a Bridging Header.
Just import it like this in your AppDelegate:
import AWSMobileAnalytics
then
AWSMobileAnalytics(forAppId: "yourID")
I am migrating a UIViewController class to train a bit with Swift. I am successfully using Objective-C code via the bridging header but I have the need of importing a constants file that contains #define directives.
I have seen in Using Swift with Cocoa and Objective-C (Simple macros) the following:
Simple Macros
Where you typically used the #define directive to define a primitive constant in C and Objective-C, in Swift you use a global constant instead. For example, the constant definition #define FADE_ANIMATION_DURATION 0.35 can be better expressed in Swift with let FADE_ANIMATION_DURATION = 0.35. Because simple constant-like macros map directly to Swift global variables, the compiler automatically imports simple macros defined in C and Objective-C source files.
So, it seems it's possible. I have imported the file containing my constants into the bridging header, but I have no visibility from my .swift file, cannot be resolved.
What should I do to make my constants visible to Swift?
UPDATE:
It seems working with NSString constants, but not with booleans:
#define kSTRING_CONSTANT #"a_string_constant" // resolved from swift
#define kBOOL_CONSTANT YES // unresolved from swift
At the moment, some #defines are converted and some aren't. More specifically:
#define A 1
...becomes:
var A: CInt { get }
Or:
#define B #"b"
...becomes:
var B: String { get }
Unfortunately, YES and NO aren't recognized and converted on the fly by the Swift compiler.
I suggest you convert your #defines to actual constants, which is better than #defines anyway.
.h:
extern NSString* const kSTRING_CONSTANT;
extern const BOOL kBOOL_CONSTANT;
.m
NSString* const kSTRING_CONSTANT = #"a_string_constant";
const BOOL kBOOL_CONSTANT = YES;
And then Swift will see:
var kSTRING_CONSTANT: NSString!
var kBOOL_CONSTANT: ObjCBool
Another option would be to change your BOOL defines to
#define kBOOL_CONSTANT 1
Faster. But not as good as actual constants.
Just a quick clarification on a few things from above.
Swift Constant are expressed using the keywordlet
For Example:
let kStringConstant:String = "a_string_constant"
Also, only in a protocol definition can you use { get }, example:
protocol MyExampleProtocol {
var B:String { get }
}
In swift you can declare an enum, variable or function outside of any class or function and it will be available in all your classes (globally)(without the need to import a specific file).
import Foundation
import MapKit
let kStringConstant:String = "monitoredRegions"
class UserLocationData : NSObject {
class func getAllMonitoredRegions()->[String]{
defaults.dictionaryForKey(kStringConstant)
}
simple swift language don't need an macros
all #define directives.
will be let
and complex macros should convert to be func
The alternative for macro can be global variable . We can declare global variable outside the class and access those without using class. Please find example below
import Foundation
let BASE_URL = "www.google.com"
class test {
}