In XCode 9's Metal template, there is one part where it's setting attributes and layouts on a MTLVertexDescriptor.
let mtlVertexDescriptor = MTLVertexDescriptor()
mtlVertexDescriptor.attributes[VertexAttribute.position.rawValue].format = ...
mtlVertexDescriptor.attributes[VertexAttribute.texcoord.rawValue].format = ...
I tried hard, but cannot figure out where the magic keywords position, texcoord and later meshPositions, meshGenerics are coming from.
I guess it's not from the source code, but I didn't find any documentation where these would be specified. For VertexAttribute all I got was the reference page, without any mention about position and texcoord.
XCode points me to ShaderTypes.h, namely this section:
typedef NS_ENUM(NSInteger, VertexAttribute) {
VertexAttributePosition = 0,
VertexAttributeTexcoord = 1,
};
I feel this is the key for understanding this, but I have multiple problems:
As a developer who started with Swift, in a Swift project template this Obj-C part is a bit confusing. Can you explain me clearly what it does exactly?
How does VertexAttributePosition in an NS_ENUM add a magical property .position and VertexAttributeTexcoord -> .texcoord?
Why are none of these documented (Google finds mostly OpenGL related pages), nor can XCode find any help / jump to definition on them?
The clue to understanding what's going on here can be found on this line in the ShaderTypes.h file:
// Header containing types and enum constants shared between Metal shaders and Swift/ObjC source
The express intent of ShaderTypes.h is to declare types that can be used by both the shaders (which are written in Metal Shading Language, a dialect of C++) and the renderer class (which is written in Objective-C or Swift, depending on which you select when opening the template). The way this is achieved is by constructing a header file that can be included in both. The twist comes when using Swift, because Swift lacks a notion of header files except for one special case: bridging headers.
When incorporating C or Objective-C code into a Swift app, you provide a bridging header that imports or declares types and methods you want to use in Swift. In Xcode, you configure this with the "Objective-C Bridging Header" setting in the "Swift Compiler - General" portion of your project's Build Settings. It's kinda buried, but if you go there, you'll see that it's populated with the "ShaderTypes.h" header from the template. That's how your Swift code knows about the VertexAttribute enum type.
In Objective-C, to get the attribute index, you'd use one of the defined enum values directly: VertexAttributePosition, which is functionally equivalent to a literal 0. When that gets imported into Swift, the name of the enum (VertexAttribute) gets stripped off the front, and the values get transformed into lower camel case, per Swift style, e.g. position. You can read more about the particulars here.
The upshot of this is that even though there is no enum value named "position" anywhere in the code, that name gets synthesized for you when you use the Objective-C enumeration from Swift. The rawValue property is the integer value associated with that particular enum value, which can then be used as an index on an attribute or vertex descriptor (again, in this case, it's equal to 0).
None of these are documented because they're defined exclusively in this template. They're not part of the Metal API or really any API; they're just names that provide a convenient label for the underlying constants, in order to make the shader and app code consistent with one another.
Related
I have an Objective C++ program used to handle the setup of our different applications. Is there a way to use preprocessor defines to create text to be substituted in the strings used by NSTextFieldCell, NSButtonCell?
FOR EXAMPLE, instead of have an NSTextField that says "Options for setting up Foo", there would be a preprocessor macro (GCC_PREPROCESSOR_DEFINITIONS):
MY_PROGRAM_NAME=Bar
and then the text for NSTextField would be:
"Options for setting up $(MY_PROGRAM_NAME)"
Which would then have the desired result: "Options for setting up Bar"
NOTE 1: obviously, I could do the substitution programmatically in code.
Note 2: this is for Xcode 7, so perhaps there isn't a feature like this?
In a word, no. The Xcode nib compiler doesn't perform any kind of variable substitution and—once encoded—all archived property values are static.
However, if this is a "thing" for you application, and there aren't too many view classes involved (say, just NSTextField), it wouldn't be hard to roll your own solution.
I'd consider this approach:
Concoct a simple-to-substitute syntax, a la "Some string {VAR_NAME}".
Define your variables as key/value pairs in a dictionary. Store the
dictionary as an XML file / dictionary in the app bundle.
At app startup, load the dictionary and make it public by putting it in
a global variable or adding it to -[NSUserDefaults registerDefaults:]
Subclass NSTextField (as an example). Override either
-initWithCoder: or -awakeFromNib. In the override, get the string
value of the view object, scan it for substitutions using the public
variable dictionary, and update the string property as appropriate.
In IB, change the class of any NSTextField that needs this feature to
your custom subclass.
Another possible approach would be to have multiple targets in your project and a separate Localizable.strings file for each of these. This of course assumes, that you use Localizable.strings, even if you may support only one language.
I've been trying to locate a transition guide for Swift 2, in particular things developers should be aware of when migrating Swift 1/1.2 codebases over to Swift 2. Obviously you have the migration assistant in Xcode, but that only really covers the donkey work and not the stuff that requires a bit more intelligent thought.
Based on the resources I was able to find on Swift 2, I've put together the following checklist:
try/catch/throw error handling - to be used for recoverable errors; revise error handling code accordingly. In particular, check all uses of NSError and calling back to delegates to report recoverable errors.
Use enums conforming to ErrorType to define your own meaningful errors.
Use #available for accessing newer platform APIs - check API use against app Deployment Target and revise accordingly
protocol extensions - move as much code as possible into these to aid re-use. In particular refactor Global Functions into protocol extensions.
nullability annotations & generics - remove redundant optional bindings and type castings
Use do { } to control scope and free large resources early
Move old do { ... } while loops to repeat { } (to remove ambiguity and improve readability)
Use guard to return early and avoid excessive indentation
Use defer for cleanup code like closing files etc.
Use Option Sets rather than OR-ing values together (e.g. viewAnimationOptions = [.Repeat, .CurveEaseIn, .TransitionCurlUp])
Review public accessor specifiers which were previously only required to support testing. Use #testable and import MyApp instead.
Move single-case switch statements to the new if case .MyEnumCase(let value) = bar() where value != 42 { doThing(value) }
Use "for ... in" filtering to clean up for loops containing if filtering statements e.g. for value in mySequence where value != "" { }
native support for C function pointers - provide using closures or global functions (do not capture local context when doing so)
fix any new let/var warnings
fix any unused variable warnings
Failable initializers can now return nil before calling super.init - remove any previous workarounds required. Designated initializers still have to initialize all stored properties before returning nil however.
Sources:
https://developer.apple.com/swift/blog/?id=29
https://developer.apple.com/swift/
https://developer.apple.com/library/prerelease/ios/releasenotes/DeveloperTools/RN-Xcode/Chapters/xc7_release_notes.html#//apple_ref/doc/uid/TP40001051-CH5-SW1
https://developer.apple.com/videos/wwdc/2015/?id=106
http://www.raywenderlich.com/108522/whats-new-in-swift-2
What have I missed?
Part of the problem is that Swift 2 has continued to evolve past WWDC. So even this year's WWDC videos are already potentially out of date, or at least not the whole story.
Unfortunately, at this time there is no official "transition guide" from Apple as such.
The Swift Programming Language (Swift 2) is always updated by Apple whenever they release a new version of Swift and is therefore one of the best sources for up to date information about Swift 2 (or later). There is plenty of explanation and example code of the entire language, not just the changes, but this is definitely at least on of the best sources for the information you are looking for right now.
So I'm using a book called iOS Games by tutorials from Ray Wenderlich and trying to utilize some of the objective-C code found there to make the accelerometer control of a character in my game work. Instead of Objective-C though, I want to use Swift. I ran into an issue when trying to create a var of type GLKVector3, which represents a 3D vector. When I type in:
var raw:GLKVector3 = GLKVector3Make(irrelevant stuff)
I get the following error:
use of module GLKVector3 as type.
I have an import at the top of my swift file for GLKit:
import GLKit
Any ideas how I can get the functionality from the GLKMath files to use in my program?
Swift has added union support in version 1.2. The fields in imported unions are read-only, even if declared with var, but can be passed to and from C functions as necessary.
The release notes for Swift 1.2 imply that the fields may not be accessible at all, but they are still readable for at least the GLKit types:
Swift can now partially import C aggregates containing unions, bitfields, SIMD vector types, and other C language features that are not natively supported in Swift. The unsupported fields will not be accessible from Swift, but C and Objective-C APIs that have arguments and return values of these types can be used in Swift. This includes the Foundation NSDecimal type and the GLKit GLKVector and GLKMatrix types, among others.
With the release of beta version of Xcode 6.3/Swift 1.2 yesterday (Feb 8, 2015) it is now possible to use GLKit from Swift.
Here check my repo: https://github.com/noxytrux/SwiftGeom i actually build a whole lib for that, so you are no more forced to use GLKit or wait for Apple to implement it in swift.
There are some enum types in my iOS objective-C app that are used in different classes, for them I guess its fine to put them in a constants.h file, but what about others that are not necessarily used in multiple classes? would it be considered a bad practice?
While sapi's answer isn't wrong, here's what I have a tendency to do...
A group of constants that are used across multiple files will go into a file. Let's say all my Foo constants go in FooConstants.h.
Now another group, say the Bar constants, they'll all go in BarConstants.h.
These files will have constants, enums, and protocol definitions in them.
In the files that need the Foo constants only, I'll import FooConstants.h.
In the files that need the Bar constants only, I'll import BarConstants.h.
And depending on the project, I may have just 1 of these files, or I may have 10 or more. Usually I'll have a file called SegueNames.h, where all of my storyboard segue identifiers are created as constants and put in this file so I never misspell a segue name. I'll also usually have DefaultsKeys.h, where I keep the keys to anything I'm putting in NSUserDefaults.
And then I started realizing every now and then, I might have a file that uses 6 of these constants files, so I started creating Constants.h.
Constants.h has nothing in it except importing all the other constants files. This cleans up the top of some of my files.
But at the end of the day, I do still keep the constants organized in their own files with some sort of grouping putting common constants together. And as sapi points out, any constant that is used only in a single file should be defined within that file.
Yes, it is bad practice.
If you place all of your constants, including enums, into the one file, then importing that file becomes necessary whenever you want to reuse part of your code.
A better practice would be to group your constants by function (at whatever level is appropriate for your app), and to include constants used only in a single class in the class file itself or, if you must, in a separate header.
It depends on the context. How well organized are your classes? If it's a bit of a mess, it doesn't hurt to start with an Errors.h/m file where you define your error codes as enums in the .h file and your error domains as NSStrings in the .m file (with corresponding extern NSString * const in your .h file).
If your organization is a bit better, then you've divided your classes into modules and each module has an entry point, where you should be defining these things. The result doesn't change though: Error header for enum values and extern declarations, error implementation for extern assignments.
All my error declaration files look like this:
// ErrorFile.h
typedef enum {
ModuleErrorOne = 1,
ModuleErrorTwo,
ModuleErrorThree
} ModuleError;
extern NSString * const ModuleErrorDomain;
// ErrorFile.m
NSString * const ModuleErrorDomain = #"ModuleErrorDomain";
You can stick it in your pre-compiled header for a compilation speed boost.
EDIT: Thanks for the comments nhgrif and GraniteRobert, they've improved my answer.
I am very confused on the MonoTouch dictionary limitation: http://docs.xamarin.com/ios/about/limitations#Value_types_as_Dictionary_Keys
My understanding that code like this is not allowed:
var foo = new Dictionary<int, int>();
But I see code in books like this, which doesn't make sense:
protected Dictionary<int, CustomCellController> _cellControllers = new Dictionary<int, CustomCellController>();
Also, someone posted that if you use nullable types, it convers the values into reference so the following works (as long as the key is not null):
var foo = new Dictionary<int?, int?>();
That also doesn't make sense, because nullable types are structs which are value types.
So what are the real rules about using dictionaries on a device?
Since no JITin is allowed on devices all code must be compiled with the AOT (ahead of time) compiler.
My understanding that code like this is not allowed:
This limitation is about the difficulties, for the AOT compiler, of determining what will be used at runtime. Such code might work and you'll see such code in samples - but it can also fail depending on what you do with the code (creating a Dictionary is not the problem).
So what are the real rules about using dictionaries on a device?
Using value-types means that the generated code cannot be shared (like it can for reference types). E.g. Using a generic Dictionary with int and long requires separate code, while the same code can be shared for string and CustomCellController.
Finding what Dictionary<int,int> needs is not the issue (it's pretty clear). However it's often in the internals that things gets complicated, e.g. ensuring the right KeyValuePair is generated. Nested generics are also hard to get right.
This is why the first general workaround is to try to hint the AOT compiler about what's needed. If the AOT compiler can find code that requires it to generate what's needed then it will be available at runtime.
The next workaround is to try to use a reference type (e.g. a string) instead of the value-type (since that case is simpler to handle for the AOT compiler).
Finally the AOT compiler is getting better (by each release) and works continues to reduce this (and other) limitation(s). So what you read here might not apply in 3, 6, 12 months...