Cannot access enum case's rawvalue defined in a global constants file - swift

I have a global constants file: Constants.swift in an iOS app project. Xcode version is 11.1.
The code in this file:
import Foundation
struct Constants {
enum DayOfTheWeekend : Int {
case Saturday = 1
case Sunday = 2
}
}
In a different file in the same iOS app project, I have this code in a func within a class:
let day = Constants.DayOfTheWeekend.Saturday.rawvalue
And I get this error:
Value of type 'Constants.DayOfTheWeekend' has no member 'rawvalue'
If I put enum outside of the struct in the same Constants.swift file, I still get the same error.
When I type "Constants.DayOfTheWeekend.Saturday.", Xcode autocomplete feature suggests only "self" and "hashvalue". There is not any rawvalue option.
Where is my mistake?

The syntax is rawValue. See The Swift Programming Language: Enumerations: Raw Values.
Why do you think Xcode autocomplete doesn't suggest that?
It does:
But sometimes autocomplete gets confused, especially if there are some errors elsewhere in one’s code. It also won’t work if the file with the enumeration hasn’t been saved. And sometimes it just gets sufficiently confused that you have to empty the derived data folder and restart Xcode.

Related

Where can I find the official UTTypeItem constant?

It's possible to register an NSView for all dragged types using the elusive UTTypeItem which allegedly replaces kUTTypeItem pasteboard type (now deprecated).
However, when I specify UTTypeItem, the Swift compiler tells me that it can't find this constant.
Eg: controlView.registerForDraggedTypes([UTTypeItem]) gives an error
When I try and compile this code, the Swift compiler helpfully says, "Did you mean kUTTypeItem ?", which gets me nowhere, of course. I tried importing CoreServices but couldn't find it there.
After a bit of digging, I found that I could define UTTypeItem for myself using a rawValue as below:
private let UTTypeItem = NSPasteboard.PasteboardType.init("public.item")
"public.item" is, of course, the under-the-covers value of UTTypeItem. This works fine, and the compiler is happy, but I think this approach is inelegant.
So my question is: where can I fing the "official" location of UTTypeItem ?
Dave
First, to use UTType you need to import UniformTypeIdentifiers:
import UniformTypeIdentifiers
This will then give you access to UTType.item. But since you need a String to pass it to the NSPasteboard, you need to access the identifier property.
let uti = UTType.item.identifier // Gives "public.item"
let pasteboardType = NSPasteboard.PasteboardType.init(uti)
If you need this is more than one place in your project you can add an extension:
import UniformTypeIdentifiers
extension NSPasteboard.PasteboardType {
static let item = NSPasteboard.PasteboardType(UTType.item.identifier)
}
Now you can use it like:
controlView.registerForDraggedTypes([ .item ])

Use of unresolved identifier: kCGWindowImageDefault (and other Core Graphics constants)

I'm new to Swift development. I'm writing an app for MacOS (not iOS) in Swift, and am trying to adapt some of the code from this Apple sample Objective-C project for use in my program.
The problem I'm hitting is that certain Apple-defined constants such as kCGWindowImageDefault and kCGWindowListOptionAll are causing XCode to report the compile-time error "Use of unresolved identifier [identifier]".
Somewhat surprisingly, though, if I right-click kCGWidowImageDefault and select "Jump to Definition", XCode does jump to the definition of that constant (in CoreGraphics > CGWindow.h > CGWindowImageOption) -- so XCode does seem to know what that constant is.
Here are the relevant snippets of my ViewController.swift file:
import Cocoa
import CoreGraphics
class ViewController: NSViewController {
...
func myFunction() {
// *** XCode reports the error on kCGWindowImageDefault on this line:
let imageOptions : CGWindowImageOption = kCGWindowImageDefault
...
}
}
The Apple documentation (as linked above) doesn't indicate what needs to be imported for these constants to be used.
XCode does appear to successfully recognize the types I'm using such as CGWindowImageOption -- it's just the constants that it isn't recognizing.
What do I need to do in order to successfully be able to use kCGWindowImageDefault and similar constants in my Swift MacOS program?
kCGWindowImageDefault is only for Objective-C, not Swift. In Swift, CGWindowImageOption is an OptionSet. For the default you simply use an empty option set:
let imageOptions : CGWindowImageOption = []
For CGWindowListOption you can do:
let listOptions: CGWindowListOption = .optionAll
Be sure you look at the Swift reference documentation for these enumerations. You can't use the Objective-C values.

Why private is unaccessible to the extension?

Here is my ViewController.swift file:
class ViewController: UIViewController {
private var myInt = 10
}
extension ViewController {
func printMyInt() {
print(myInt)
}
}
Although as mentioned in the Swift documentation - Access Levels section:
Private access restricts the use of an entity to the enclosing
declaration, and to extensions of that declaration that are in the
same file. Use private access to hide the implementation details of a
specific piece of functionality when those details are used only
within a single declaration.
Since Swift 4 has been released, I assume that I am able to implement such a thing (it is also mentioned in: What's New in Swift - WWDC 2017 session), however, the complier shows me:
'myInt' is inaccessible due to 'private' protection level
Is it incompatible with what mentioned in the documentation?
As a simple quick solution, I could declare it as:
fileprivate var myInt = 10
but I wonder why is it behaves like this, am I misunderstand what mentioned in the documentation? or is it a "Xcode" bug (used 9.0.1 version)?
Remark: The project has been created in the older Xcode 8 and then migrated to Xcode 9.
In Swift 4, private members are accessible to extensions of that declaration that are in the same file, see SE-0169 – Improve Interaction Between private Declarations and Extensions.
If the project has been created in Xcode 8 (with Swift 3) then
Xcode 9 will open it in "Swift 3 mode" and set the "Swift Language Version" to "Swift 3.2". Therefore the stricter Swift 3 restrictions hold.
To make the private extension visible to extension in the same file,
set the Swift language version to 4 in the build settings. (Of course
that might make more changes in your code necessary.)
Even better, use "Edit -> Convert -> To Current Swift Syntax ..."

Xcode 7.3 undeclared type for Obj C enum in Swift code

In my project I have Swift extensions over Objective C enums, which worked brilliantly in Xcode 7.2.
But with Xcode 7.3 it fails with "undeclared type" in the Swift file where I extend the Obj C enum.
I've built a sample project and it compiles and works well, but I can't make the existing project accept the extension over the Obj C enum.
UPDATE:
After reinstalling Xcode 7.2 I can confirm that the project compiles and builds successfully.
After it worked in Xcode 7.2, I tried launching this project again in Xcode 7.3 and again the same issue -> the Swift extension over Obj C enums can't be build.
After cleaning and deleting the derived data in Xcode 7.3 I receive also the -Swift.h header missing error because the Swift classes haven't been compiled so a header wasn't created yet.
Code explanation:
My Obj C enum inside "FriendRequestResult.h":
typedef NS_ENUM(NSInteger, FriendStatus)
{
FriendStatusRequestedByUser = 1,
FriendStatusRequestedByOtherUser,
FriendStatusFriends,
FriendStatusBlocked,
FriendStatusNone,
FriendStatusError,
};
Now, as expected in my AppName-Bridging-Header.h I have:
#import "FriendRequestResult.h"
Then, I have the swift extension over the FriendStatus which builds in Xcode 7.2, but fails with "use of undeclared type" in Xcode 7.3:
extension FriendStatus
{
init(stringValue : String?)
{
if let stringValue = stringValue
{
switch stringValue
{
case "REQUESTED_BY_USER": self = .RequestedByUser
case "REQUESTED_BY_OTHER": self = .RequestedByOtherUser
case "FRIENDS": self = .Friends
case "BLOCKED": self = .Blocked
default: self = .None
}
}
else
{
self = .None
}
}
}
Actually this extension over the enum has also some other helper functions, but that should not change the problem in any way.
Of course if the extension of the enum gives the undeclared type, then using this type fails everywhere in the Swift code with the same "undeclared things". Basically the enum is not visible at all for the Swift part of the project, even though the import is made in the bridging header.
This question was substantially edited from its first version.
Solution 1:
Moved the enum in a seaparate header file.
My enum declaration was in the same header as a class header and specifically it was between the #interface and #end of that class.
In Xcode 7.2 it was creating no issues and the parsing of the header was successful, while in Xcode 7.3 they probably optimised something and changed the way it's parsed, so it was seeing my class, but not the enum inside it [maybe it declares it as private if it's inside a class declaration]
Solution 2: Moved the enum declaration outside the #interface #end scope.
To answer your question: "Can I somehow force Xcode to generate the Swift header first? Or can I force Xcode to believe that my enums exist somewhere and that it should validate my extensions?"
I found 2 ways to order file compilation.
Using a target and making it a dependency of your project.
Opening the project.pbxproj file and editing the list manually.
Depending on the level of risk and complexity you are ready to tackle, pick one or the other.
I just tried extending an ENUM and things are working fine here. One issue I had in the past was understanding the name stripping convention between Obj-C and Swift but this doesn't look like the issue you are running into.
The other issue I encounter invariably is maintaining the ##$% Bridging-Header.h file all the time. Are you positive this is up-to-date?

xcode 6 beta 4 new Swift issues with NS_ENUM defined in Objective C

Just started to use Xcode6 beta 4 and have come up against an issue that was not there before. I define my NS_ENUM in my objective-c as follows:
typedef NS_ENUM( NSInteger, ToolbarType ) {
tb_closed_k = 0,
tb_text_k = 10,
tb_shape_k,
tb_undefined_k
};
Then in my swift code i want to set a variable to one of these values:
var test = ToolbarType. tb_undefined_k
This was working without issues in beta 3 but now I get an error that :
'ToolbarType' does not have a member named 'var test = ToolbarType. tb_undefined_k'
After investigating further, if I type the enum type followed by a ., auto completion shows me the options and it suggests the value to be:
ToolbarType.b_undefined_k
is seems very odd. Is this a bug or some kind of naming convention? I am afraid if I use these suggested values, in the next release they all become broken.
Any suggestions. Thanks.
Reza
After playing around I found that if I added a value to the end of the enum that did not in anyway conform to the naming convention of the values that proceeded it then the error would go away. In fact I just added "dummy" to the end my list of enums and it all started to work