Strange exception in layouts - xcode

Try call this method:
avatarIconImageView.setContentHuggingPriority(UILayoutPriorityDefaultLow, forAxis: UILayoutConstraintAxis.Horizontal)
and catch this exception:
Undefined symbols for architecture armv7:
"_UILayoutPriorityDefaultLow", referenced from:
__TFC13TCProject_iOS36TCAvatarWithCounterUniversalCellView22configureBodyCellViewsfS0_FT_T_
in TCAvatarUniversalCellView.o ld: symbol(s) not found for
architecture armv7 clang: error: linker command failed with exit code
1 (use -v to see invocation)
what it means?

This looks like a bug in the iOS 8 SDK. You can work around this by just passing in a raw value.
UILayoutPriorityDefaultRequired = 1000
UILayoutPriorityDefaultHigh = 750
UILayoutPriorityDefaultLow = 250
In your case
avatarIconImageView.setContentHuggingPriority(250, forAxis: UILayoutConstraintAxis.Horizontal)

This is not a bug. It is a shortcoming of an expectation for the import of Objective-C libraries into Swift. It should be understood how Swift imports code (even from the Apple UIKIt Libraries) from Objective-C into Swift.
UILayoutPriority is a float. In Objective-C, a couple of values have been pre-defined for us. The pre-defined values appear to be an enum. We might expect that the same enums would be available to us in Swift.
The documentation suggests an enum:
Declaration
SWIFT
typealias UILayoutPriority = Float
OBJECTIVE-C
enum {
UILayoutPriorityRequired = 1000,
UILayoutPriorityDefaultHigh = 750,
UILayoutPriorityDefaultLow = 250,
UILayoutPriorityFittingSizeLevel = 50,
};
typedef float UILayoutPriority;
But in Xcode, if you ask to see the defintion of one of these enum values (UILayoutPriorityRequired, for example), you will see that they are actually defined in the header file as constant floats.
typedef float UILayoutPriority;
static const UILayoutPriority UILayoutPriorityRequired NS_AVAILABLE_IOS(6_0) = 1000; // A required constraint. Do not exceed this.
static const UILayoutPriority UILayoutPriorityDefaultHigh NS_AVAILABLE_IOS(6_0) = 750; // This is the priority level with which a button resists compressing its content.
static const UILayoutPriority UILayoutPriorityDefaultLow NS_AVAILABLE_IOS(6_0) = 250; // This is the priority level at which a button hugs its contents horizontally.
So although we may like to think of the pre-defined layout priorities as enum values (as the documentation suggests) the layout priorities are not really defined as enums; they are defined as constant floats.
A hint for anyone that knows the C programming language is that a C enum may only contain int values. The following is legal and will compile:
enum myEnum {
JGCEnum_one = 1,
JGCEnum_two,
JGCEnum_three
} JGCEnum;
But we can't really define floats as values for C enums. The following will not compile:
enum myEnum {
JGCEnum_one = 1.5, // compilation error
JGCEnum_two,
JGCEnum_three
} JGCEnum;
Objective-C enums are the same as C enums (Swift enums are different). It is important to know if we are dealing with actual integers or floats. Because integers can be defined using the NS_ENUM macro, which can then be imported to Swift as a Swift enum.
The iBook says
Swift imports as a Swift enumeration any C-style enumeration marked with the NS_ENUM macro. This means that the prefixes to enumeration value names are truncated when they are imported into Swift, whether they’re defined in system frameworks or in custom code.
Excerpt From: Apple Inc. “Using Swift with Cocoa and Objective-C.” iBooks. https://itun.es/us/1u3-0.l
That means that if UILayoutPriority had been defined as an integer using the NS_ENUM macro, it would have been imported into Swift as Swift enum. This is the case for UILayoutConstraintAxis.
Declaration
SWIFT
enum UILayoutConstraintAxis : Int {
case Horizontal
case Vertical
}
OBJECTIVE-C
enum {
UILayoutConstraintAxisHorizontal = 0,
UILayoutConstraintAxisVertical = 1
};
typedef NSInteger UILayoutConstraintAxis;
Looking at the Objective-C header file confirms what the documentation says.
//
// UIView Constraint-based Layout Support
//
typedef NS_ENUM(NSInteger, UILayoutConstraintAxis) {
UILayoutConstraintAxisHorizontal = 0,
UILayoutConstraintAxisVertical = 1
};
So there are at least two ways to know if a pre-defined value you are used to using in Objective-C is available in Swift:
check the documentation
check the header file in Objective-C (found by right-clicking the value and then selecting "Jump to Definition")
There is one more way to see if a typedef you are used to using is a constant or an enum. In code, test to see if the address of the constant exists. Constants have a memory address, while enums do not. See the code below.
// this line will compile and run just fine.
// UILayoutPriorityDefaultHigh is a constant and has a memory address
// the value will be true if the device is running iOS 6.0 or later
// and false otherwise
BOOL predefinedValueIsAvailable = (NULL != &UILayoutPriorityDefaultHigh);
// this line will not compile
// UILayoutConstraintAxisHorizontal is an enum (NOT a constant)
// and does not have a memory address
predefinedValueIsAvailable = (NULL != &UILayoutConstraintAxisHorizontal);
References
https://www.blogger.com/blogger.g?blogID=1591443959382526146#editor/target=post;postID=5044844235580349879;onPublishedMenu=allposts;onClosedMenu=allposts;postNum=0;src=postname
Xcode Documentation (iOS 8.2)
Apple Inc. “Using Swift with Cocoa and Objective-C.” iBooks. https://itun.es/us/1u3-0.l

Related

Why does SDL_GetWindowWMInfo() require SDL version?

According to the documentation for
SDL_bool SDL_GetWindowWMInfo(SDL_Window* window,
SDL_SysWMinfo* info)
SDL_SysWMinfo* info's SDL_Version version member must be defined by the SDL_VERSION macro at compile time before it is passed.
Why does SDL_GetWindowWMInfo require the SDL version the calling code was compiled against? What would happen if SDL_GetWindowWMInfo did not check the SDL version?
It's pretty much like keltar said. This is from SDL_windowswindow.c:
SDL_bool
WIN_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
{
const SDL_WindowData *data = (const SDL_WindowData *) window->driverdata;
if (info->version.major <= SDL_MAJOR_VERSION) {
info->subsystem = SDL_SYSWM_WINDOWS;
info->info.win.window = data->hwnd;
info->info.win.hdc = data->hdc;
return SDL_TRUE;
} else {
SDL_SetError("Application not compiled with SDL %d.%d\n",
SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
return SDL_FALSE;
}
}
This function fills in a user-provided struct. The danger is that this struct is liable to change as the platform support in SDL changes (as opposed to actual feature/API changes that are more apparent in a new version number).
If that struct definition has changed between versions of SDL (say, you use updated headers but old dll), this requirement allows SDL to detect the problem before it stomps your program's memory.

cs193p, 2015, Lesson 02, function overloading [duplicate]

I am starting to learn Swift, and have been following the very good Stanford University video lectures on YouTube. Here is a link if you are interested or it helps (although it isn't required to understand my problem):
Developing iOS 8 Apps with Swift - 2. More Xcode and Swift, MVC
While following the lectures I got to a point where (as far as I could tell) my code was identical to the code in the video but on my system I got a compiler error. After a lot of trial and error I have managed to reduce my code to two examples, one of which generates an error, the other or which doesn't, but I have no idea what is actually causing the error or how to resolve it.
The code which creates the error is:
import UIKit
class BugViewController: UIViewController
{
func perform(operation: (Double) -> Double) {
}
func perform(operation: (Double, Double) -> Double) {
}
}
This creates the following compiler error:
Method 'perform' with Objective-C selector 'perform: ' conflicts with previous declaration with the same Objective-C selector
By simply removing the sub-classing of UIViewController the code compiles:
import UIKit
class BugViewController
{
func perform(operation: (Double) -> Double) {
}
func perform(operation: (Double, Double) -> Double) {
}
}
Some other information which may or may not be relevant:
I have recently upgraded to Yosemite.
When I installed Xcode, I ended up with a Beta version (Version 6.3 (6D543q)) because (if I remember correctly) this was the version I needed to run on my version of OS X.
I am half hoping this is a bug in the compiler because otherwise this doesn't make any sense to me. Any help very gratefully received!
I myself am also taking the Standford course and I got stuck here for a long time too, but after some searching, I found something from here: Xcode release notes and it mentioned something below:
Swift 1.2 is strict about checking type-based overloading of #objc
methods and initializers, something not supported by Objective-C.
// Has the Objective-C selector "performOperation:".
func performOperation(op: NSOperation) { /* do something */ }
// Also has the selector "performOperation:".
func performOperation(fn: () -> Void) {
self.performOperation(NSBlockOperation(block: fn))
}
This code would work when invoked from Swift, but could easily crash
if invoked from Objective-C. To solve this problem, use a type that is
not supported by Objective-C to prevent the Swift compiler from
exposing the member to the Objective-C runtime:
If it makes sense, mark the member as private to disable inference of #objc.
Otherwise, use a dummy parameter with a default value, for
example: _ nonobjc: () = (). (19826275)
Overrides of methods exposed
to Objective-C in private subclasses are not inferred to be #objc,
causing the Swift compiler to crash. Explicitly add the #objc
attribute to any such overriding methods. (19935352)
Symbols from SDKs are not available when using Open Quickly in a
project or workspace that uses Swift. (20349540)
what i did was just adding "private" in front of the override method like this:
private func performOperation(operation: Double -> Double) {
if operandStack.count >= 1 {
displayValue = operation(operandStack.removeLast())
enter()
}
}
Objective-C does not support method overloading, you have to use a different method name. When you inherited UIViewController you inherited NSObject and made the class interopable to Obj-C. Swift on the other hand does support overloading, that's why it works when you remove the inheritance.
As it has already been answered, ObjC doesn't support method overloading (two methods with the same name) and In swift 2 under Xcode 7 there are two options to solve this kind of problems. One option is to rename the method using the attribute: #objc(newNameMethod:)
func methodOne(par1, par2) {...}
#objc(methodTwo:)
func methodOne(par1) {...}
another option to solve this problem in Xcode 7+ is by applying #nonobjc attribute to any method, subscript or initialiser
func methodOne() {...}
#nonobjc
func methodOne() {...}
The problem is UIViewController is an #objc class. When inheriting from UIViewController, BugViewController is also a #objc class.
This means it must conform to the rules of Objective-C selectors (the name of a method). The methods func perform(operation: (Double) -> Double) and func perform(operation: (Double, Double) -> Double) both have the same selector #selector(perform:). This is not allowed.
To resolve this, use different names: like func perform1(operation: (Double) -> Double) and func perform2(operation: (Double, Double) -> Double).
I think the best way to handle this is to give your perform() methods more descriptive names. What do these methods do? How do they change the state of the view controller? Look at the other UIViewController methods to get a feel for the style of method naming, or read Method Names Should Be Expressive and Unique Within a Class
From https://developer.apple.com/library/ios/releasenotes/DeveloperTools/RN-Xcode/Chapters/xc6_release_notes.html under "Xcode 6.3 Release Notes" -> "Swift Language Changes" you find
Swift now detects discrepancies between overloading and overriding in the Swift type system and the effective behavior seen via the Objective-C runtime.
I got the same error due to having having two methods with the same Obj-C signature:
static func prepareForUpSyncing(obj : NSManagedObject!) -> Bool
static func prepareForUpSyncing(objs : [NSManagedObject]!) -> Bool
I didn't want to mark one of them as #nonobjc due to possibility of unforseen consequences at runtime. (Someone can correct me if there is no possibility)
Resolved it by using Swift's external parameter name feature (I made external name same as local name) to the second method, which effectively changes the Obj-c method signature:
static func prepareForUpSyncing(objs objs : [NSManagedObject]!) -> Bool {

Searching Serial Ports with IOKit - Swift

I'm trying to understand IOKit and how it allows me to access serial ports in a Swift program.
The class I'm manipulating at the moment is as follows:
import Foundation
import Cocoa
import IOKit.serial.IOSerialKeys
class Serial {
init() {
}
#IBOutlet var serialListPullDown : NSPopUpButton!
func refreshSerialList(defaultprompt: String) {
// remove everything from the pull down list
serialListPullDown?.removeAllItems()
// ask for all the serial ports
IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching(kIOSerialBSDServiceValue), io_iterator_t)
}
}
Based on what I've read I think I've setup IOServiceMatchingServices correctly but I'm getting several errors such as "Expected member name or constructor call after type name" and "'o_iterator_t.Type' is not convertible to 'UnsafeMutualPointer'"
What does this mean?
A few different issues going on in there -- let's get your imports squared away first. It looks like you need these two:
import IOKit
import IOKit.serial
For the parameters, it'll be easier to see what we're working with if we define them as local variables, like so:
// this one's easy, just grabbing a constant from IOKit.serial
let masterPort: mach_port_t = kIOMasterPortDefault
// here we get back an Unmanaged<CFMutableDictionary> and need to convert it to
// a CFDictionary using takeRetainedValue()
let classesToMatch: CFDictionary = IOServiceMatching(kIOSerialBSDServiceValue).takeRetainedValue()
// the iterator that will contain the results of IOServiceGetMatchingServices
var matchingServices: io_iterator_t = 0
And lastly, you call the method:
// note that the last parameter is an UnsafeMutablePointer<io_iterator_t>
// so we need to prefix matchingServices with an ampersand (&)
let kernResult = IOServiceGetMatchingServices(masterPort, classesToMatch, &matchingServices)
if kernResult == KERN_SUCCESS {
// success
} else {
// error
}
This feels pretty near the edge of what Swift can handle right now -- definitely read these two pages well before going further:
Interacting with C APIs (Pointers section)
Working with Cocoa Data Types (Unmanaged Objects section)
Lastly, make sure you can get into the converted Swift declarations for the IOKit framework. There are a lot of useful comments and you'll be able to see which parameters and return values are unmanaged or pointers (since I don't think this framework's official documentation has been updated yet).

'Class.Type' does not have a member named 'variable' error just a lack of class variable support?

I have been trying to use constants and variables in a class that refer by name to other constants and variables in the same class at the class level. AFAIK, as of Xcode 6 beta 4, Swift still doesn't have class variable support. What I'm wondering is whether the errors I see when trying to refer to other constants (let) or variables (var) are simply due to lack of class variable support?
You can refer to the constants and variables within a method or outside the class, you just don't seem to be able to reference by name at the class level. The following class shows several variations along with the errors you will see displayed in Xcode 6 beta 4.
This can be tested in a playground or regular .swift file.
class Simple {
let someConstant = 0.50
var someVariable = 1
// uncomment let and var lines to see the errors
// error: 'Simple.Type' does not have a member named 'someConstant'
// let referringConstant = someConstant
// error: Use of unresolved identifier 'self'
// let referringConstant = self.someConstant
// error: 'Simple.Type' does not have a member named 'someVariable'
// var referringVar = someVariable
// error: Use of unresolved identifier 'self'
// var referringVar = self.someVariable
// can't do class constants or variables yet either
// let referringConstant = Simple.someConstant
// var referringVar = Simple.someVariable
func simpleMethod() {
// both of these forms are valid as long as it is unambiguous
let referToConstant = someConstant
let referToVariable = someVariable
var anotherConstant = self.someConstant
var anotherVariable = self.someVariable
}
}
For reference, the original Objective-C code that led to this problem in Swift was from the CS193P SuperCard app where a C #define is used for a constant and then that constant is used to set a variable.
#interface PlayingCardView()
#property (nonatomic) CGFloat faceCardScaleFactor;
#end
#implementation PlayingCardView
#pragma mark - Properties
#synthesize faceCardScaleFactor = _faceCardScaleFactor;
#define DEFAULT_FACE_CARD_SCALE_FACTOR 0.90
- (CGFloat)faceCardScaleFactor
{
if (!_faceCardScaleFactor) _faceCardScaleFactor = DEFAULT_FACE_CARD_SCALE_FACTOR;
return _faceCardScaleFactor;
}
- (void)setFaceCardScaleFactor:(CGFloat)faceCardScaleFactor
{
_faceCardScaleFactor = faceCardScaleFactor;
[self setNeedsDisplay];
}
The two errors messages you're getting are actually a result of two different, but related, reasons.
error: Use of unresolved identifier 'self'
self refers to an instance of a type and does not exist until that type is considered fully initialized, and therefore cannot be used for default property values.
error: 'Simple.Type' does not have a member named 'someConstant'
Class variables and static variables are considered "type variables" of classes and structs, respectively. What this means is that they're defined as variables on the type itself, as opposed to an instance of that type. By this definition and the fact that you can't use self for default property values, it's clear that this error message is a result of Swift looking for a class variable named someConstant. Class variables are still not supported as of Beta 4.
The analogous code for structs, with type variables taken into account, compiles just fine:
struct Simple {
static let someConstant = 0.50
static var someVariable = 1
let referringConstant = someConstant
var referringVar = someVariable
let explicitTypeProperty = Simple.someConstant
}
Reference: my recollection of the "Properties" and "Initializers" chapters of The Swift Programming Language.

Retain a random number across different functions in Cocoa?

I know how to do a global variable, but whenever I try to define a global variable with a random number function, xcode says "initializer element is not constant." The compiler doesn't want to make a variable from a random number because the random number function is not constant.
How do I generate a random number and then use that same value for more than one action? (For example, to define a color and then write that value to a label?)
Code:
#import "Slider_with_IBAppDelegate.h"
float * const hue = ((arc4random() % ((unsigned)100 + 1))/100.0);
//^this is where I get the error: "initializer element is not constant"
#synthesize label
//write value to label
- (IBAction) doButton {
label.text = [NSString stringWithFormat:#"%f", hue];
}
//set background color
- (void)applicationDidBecomeActive:(UIApplication*)application
{
self.label5.backgroundColor = [UIColor colorWithHue:hue
saturation:1.0
brightness:1.0
alpha:1.0];
}
----edit------
Thanks for the suggestions. It still doesn't work for me, though, what am I doing wrong?
New code:
#import "Slider_with_IBAppDelegate.h"
float const hue = ((arc4random() % ((unsigned)100 + 1))/100.0);
//^I still get the error: "initializer element is not constant."
#synthesize label
//write value to label
- (IBAction) doButton {
label.text = [NSString stringWithFormat:#"%f", hue];
}
//^this is where I get the error "'hue' undeclared (first use of this function)"
//set background color
- (void)applicationDidBecomeActive:(UIApplication*)application
{
hue = ((arc4random() % ((unsigned)1000 + 1))/1000.0);
/*here I get the error "assignment of read-only variable 'hue.'"
If I insert "float" just before hue, I do not get this error,
but it still won't compile because of the error above.*/
self.label5.backgroundColor = [UIColor colorWithHue:hue
saturation:1.0
brightness:1.0
alpha:1.0];
}
Make it non-const and initialize it in applicationDidBecomeActive. Is there a reason it must be constant?
I know how to do a global variable, but whenever I try to define a global variable with a random number function, xcode says "incompatible types in initialization."
float * const hue = ((arc4random() % ((unsigned)100 + 1))/100.0);
That's not a function; it's an expression. I'd be surprised if you're not also getting an error here, because you can't initialize a global variable with an expression that isn't constant. As alltom.com says, you need to assign to it from applicationDidBecomeActive:.
The warning is because you've given the variable a pointer type (float *), but you're not assigning a pointer to it. Cut out the asterisk, because you're not going to put a pointer in this variable.
Xcode doesn't want to make a variable from a random number because the random number function is not constant.
Xcode doesn't care one way or the other. It's just reporting the findings of the compiler. By default, the compiler for Objective-C is GCC, but Xcode supports other compilers (and Xcode does come with one other C/Objective-C compiler: LLVM-GCC).
… I couldn't call the same value for the label.
You're not showing a label here, and you can't call a value. You can only call a function, and you don't have one in the code shown.
It gave me the error "function undefined: first use of this function" in doButton even though it was defined in applicationDidBecomeActive.
No, it wasn't. Assigning to a variable does not create a function.
In case anyone is wondering, I finally found a way to do this effectively. (I am sure this is what alltom was saying, I was just too dumb to understand.)
I declared a float and a seed in my .h file:
- (float)generate:(id)sender;
- (void)seed;
And in the implementation file, I defined the float as a random number, and I used srandom() as a random seed generator.
- (float)generate:(id)sender
{
//Generate a number between 1 and 100 inclusive
int generated;
generated = (random() % 100) + 1;
return(generated);
}
- (void)seed {
srandom(time(NULL));
}
Then anywhere I wanted to retain a random number, I used
srandom(time(NULL));
generated1 = ((random() % 100) + 1)/100.0;
to initiate the number, and from there I was able to use generated1, generated2, hue, etc. as variables in any function I wanted (and I made sure to declare these variables as floats at the top of the file).

Resources