Objc code cannot find Bool variable defined in swift - objective-c

I have a var defined in one Swift file, but in another Objective-C file, when I try to set this var, the complier complains it cannot find the var. How do I solve this problem? here is the code:
in swift:
var isCreating: Bool!
in objc :
SelectMemberViewController *ctrl = [[SelectMemberViewController alloc]init];
ctrl.isCreating = YES
then the complier is complaining : Property 'isCreating' not found on object of type 'SelectMemberViewController'

The problem is that nothing in Objective-C's world corresponds to a Bool!. Thus, this declaration is not exposed to Objective-C. You need to declare this a plain Bool if you want Objective-C to be able to see it.

Related

Access singleton sharedInstance in Objective-C class from Swift class in combined project

I have an objective-C project in which I have added a Swift class. I would like to access a shared instance of an Objective C class from my Swift code but I can't find any examples of how to do this. Here are a couple examples of code in Objective-C to access shared Instances that I would like to perform from Swift:
//to get property
self.managedObjectContext = [myModel sharedInstance].managedObjectContext;
//to get a string returned by a method in the sharedInstance
NSString *aUser = [[referenceClass sharedInstance] getUserName];
In the Objective-C header file for the singleton, I have
+ (referenceClass*)sharedInstance;
I have imported the classes needed such as referenceClass in my Bridging Header file but how would I get the string using Swift?
Something like: (Pseudo code)
var username: String = referenceClass.sharedInstance().getUserName()
Thanks in advance for any suggestions.
Declare your singleton class reference variable as like this
var singletonReference = YourSingletoneClass.sharedInstance() as! YourSingletoneClass
and access value using reference variable
var username: String = singletonReference.getUserName()
According to your example you can use also like this
var username: String = (referenceClass.sharedInstance() as! referenceClass).getUserName()
Note : If you want your reference variable through out your class declare globally

Using Instance Variables in Functions [duplicate]

Can someone confirm that you cannot access instance variables defined in an Objective C #implementation block from within C style functions of the same class? The compiler is throwing errors saying "XXX undeclared' where XXX is the instance variable name.
Here's an example of what I am explaining:
#interface FontManager : NSObject {
CGFontRef fontRef;
}
static int CstyleFunction() {
NSUInteger emSize = CGFontGetUnitsPerEm(fontRef);
}
I want to verify that I cannot use "fontRef" from withing "CstyleFunction".
Any insight would be greatly appreciated.
A "C style method" doesn't really deserve the name "method", I'd call it a "function" instead as in C.
A C function has no self, so it cannot implicitly access ivars as a method can. If you pass an instance to the C function as a parameter, you can access ivars in the same manner you would access a field in a struct pointer.
#Anomie and #jlehr are correct, the C function has no concept of the FontManager object and its current state, it just happens to live in the same file.
However, if FontManager is a singleton and you make fontRef a property (or create an accessor for it), then it would be possible to access the value within your C class:
static int CstyleMethod() {
FontManager *fm = [FontManager sharedManager];
NSUInteger emSize = CGFontGetUnitsPerEm(fm.fontRef);
}
Bottom line, you can mix-and-match C and ObjC syntax within C functions & ObjC methods. But because C functions have no default reference to self (and the object's associated instance variables), you can only reference ObjC objects that are singletons, stored in a global variable, or passed in as parameters.
That's correct. You seem to be mixing up methods and functions though. Methods exist only in Objective-C. What you're referring to as a 'C style method' is really just a C function.
C is not an object-oriented programming language. Since there's no such thing as an object in C, there's also no such thing as an instance variable in C, so the fontRef instance variable would not be visible in the function you posted, nor for that matter in any other C function in your program.

Cannot assign value of type UnsafeMutablePointer ObjCBool in Swift

I'm unfamiliar with Objective C.
I'm using a private framework and need to be able to change one of the properties from within my Swift code.
The property is declared in Objective C this way:
#property (nonatomic, assign) BOOL *isSSNField;
in swift I am trying to change the value of the property this way:
myClass.isSSNField = true
I am getting this error
Cannot assign a value of type 'Bool' to a value of type 'UnsafeMutablePointer<ObjcBool>'
I'm not sure where to go from here, or why I'm getting this error at all
Update for Swift 5.1
For pointer types Swift provides pointee property,
Documentation for v5.1 says it is used for accessing instance referenced by this pointer
You can easily set the pointee field
myClass.isSSNField.pointee = false
And this is same for all pointer types and conversions. If you want to check the value of an Objective C BOOL* You can easily
if myClass.isSSNField.pointee.boolValue
I've never seen anything like the situation you describe, and personally I'm tempted to say the situation doesn't exist; I have never seen a BOOL* property or ivar in Objective-C in my life (and I'm darned old, believe me). However, if you insist: I haven't tested this, but I think you could say something like this:
var ok = UnsafeMutablePointer<ObjCBool>.alloc(1)
ok[0] = false // or true
let val = ok
myClass.isSSNField = val
However, although I think that will compile, I'm rather unclear on what the implications of doing it would be. It could cause the universe to collapse to a black hole, so be careful.
BOOL* in Objective-C is a pointer of Bool.
Use UnsafeMutablePointer in Swift.
var isSSNField: ObjCBool = true
myClass.isSSNField = &isSSNField
Then fix it.
Just like the isDirectory parameter in function:
func fileExists(atPath path: String, isDirectory:UnsafeMutablePointer<ObjCBool>?) -> Bool
You can use the code:
var isDirectory:ObjCBool = true
var isFileExists = FileManager.default.fileExists(atPath: <#YourPath#>, isDirectory: &isDirectory)
The safer way to handle this would be very similar to #TanJunHao 's answer:
var isSSNField = ObjCBool(true)
myClass.isSSNField = &isSSNField
Look like your Objective C property declaration is incorrect. Please update like below and try
#property (nonatomic, assign)BOOL isSSNField;

CGContextRef/Objective C to CGContext/Swift confusion [duplicate]

I'm using an Objective-C class in my Swift project via a bridging header. The method signature looks something like this:
- (CFArrayRef)someMethod:(someType)someParameter;
I started by getting an instance of the class, calling the method, and storing the value:
var myInstance = MyClassWithThatMethod();
var cfArr = myInstance.someMethod(someValue);
Then try to get a value in the array:
var valueInArrayThatIWant = CFArrayGetValueAtIndex(cfArr, 0);
However I get the error Unmanaged<CFArray>' is not identical to 'CFArray'. What does Unmanaged<CFArray> even mean?
I looked through How to convert CFArray to Swift Array? but I don't need to convert the array to a swift array (however that would be nice). I just need to be able to get values from the array.
I have also tried the method of passing the CFArray into a function outlined in this answer:
func doSomeStuffOnArray(myArray: NSArray) {
}
However I get a similar error when using it:
doSomeStuffOnArray(cfArr); // Unmanaged<CFArray>' is not identical to 'NSArray'
I am using CFArray because I need to store an array of CGPathRef, which cannot be stored in NSArray.
So how am I supposed to use CFArray in Swift?
As explained in
Working with Core Foundation Types, there are two possible solutions when
you return a Core Foundation object from your own function that is imported in Swift:
Annotate the function with CF_RETURNS_RETAINED or CF_RETURNS_NOT_RETAINED.
In your case:
- (CFArrayRef)someMethod:(someType)someParameter CF_RETURNS_NOT_RETAINED;
Or convert the unmanaged object to a memory managed object with takeUnretainedValue() or takeRetainedValue() in Swift. In your case:
var cfArr = myInstance.someMethod(someValue).takeUnretainedValue()
An Unmanaged is a wrapper for an actual CF value. (Sort of like an optional.) It's there because ARC can't tell from looking at the declaration of someMethod: whether that method retains the value it returns.
You unwrap an Unmanaged by telling ARC what memory management policy to use for the value inside. If someMethod calls CFRetain on its return value:
let cfArr = myInstance.someMethod(someValue).takeRetainedValue()
If it doesn't:
let cfArr = myInstance.someMethod(someValue).takeUnretainedValue()
After you do that, cfArr is a CFArray, so you can use the bridging tricks from the other questions you linked to for accessing it like a Swift array.
If you own the code for someMethod you can change it a bit to not need this. There's a couple of options for that:
Annotate with CF_RETURNS_RETAINED or CF_RETURNS_NOT_RETAINED to tell the compiler what memory behavior is needed
Since it's an ObjC method, bridge to NSArray and return that--it'll automatically become an [AnyObject] array in Swift.

Swift Inheritance Issue - Cannot access inherited properties

I'm running into a strange issue that involves simple inheritance in Swift. I might be doing something totally stupid so if anyone has any advice.. thanks in advance!
I am using the latest XCode 6 GM version 6A313.
Here are the 2 Swift classes that's made Objective-C backward compatible.
#objc
public class ObjectA : NSObject {
var testProp: String!
init(testProp: String) {
self.testProp = testProp
}
}
#objc
public class ObjectB : ObjectA {
var testPropB: String!
init(testProp: String, testPropB: String) {
self.testPropB = testPropB
super.init(testProp: testProp)
}
}
I then initialize and use the object in Objective-C code.
ObjectB *objectB = [[ObjectB alloc] initWithTestProp: #"TestProp" testPropB: #"TestPropB"];
// This executes correctly and has the correct value
NSLog(#"%#", objectB.testPropB);
// I then pass this newly constructed object to another class that's written in Swift
AnotherClass *anotherClass = [[AnotherClass alloc] init];
[anotherClass someMethod:objectB];
Here is the Swift class where when I attempt to access the inherited property, I get an EXC_BAD_ACCESS code 1.
#objc
public class AnotherClass : NSObject {
public func someMethod(objectB: ObjectB) {
// This executes and assigns correctly
let prop = objectB.testProp
// This errors out with EXC_BAD_ACCESS error code 1
// In the debugger, objectB.testPropB actually seem to have the correct value
let propB = objectB.testPropB
}
}
var testProp: String!
There is no reason for this to be an implicitly unwrapped optional. You always initialize it in init. If possible, it should be:
let testProp: String
If it must be mutable after assignment, then it should be:
var testProp: String
Fixing this will probably cause the compiler to shout at you where you're doing something wrong (possibly not in the code you've posted here). With a !, it is legal to fail to initialize this value (you'll just crash later). Without a !, the compiler will better verify that you do initialize this value.
This line:
ObjectB *objectB = [[ObjectB alloc] initWithTestProp: #"TestProp", testPropB: #"TestPropB"];
is not correct ObjC (there's an extra comma). I'll assume that it's a typo. I don't think that can result in a legal C comma-operator that would cause the wrong initializer to run. But maybe... it's at least worth checking if you actually do have a comma in there. (I'm pretty sure testPropB:#"..." isn't a legal expression, so this is a little far-fetched, but it would match your symptom).
So, I ended up creating a dummy project to test my theory in a more controlled environment. The fix is basically to ensure that ObjectA and ObjectB are in 2 separate Swift files. When they are in the same Swift file, the error occurs.
Here is the sample code for anyone interested.
https://github.com/MystKnight/swift-inheritance-test
I'm not sure why this is but for everyone out there, I guess limit your files to one class if you are using inheritance...