SpriteBuilder | Cocos2d - Swift | XCode | ccPhysicsCollisionBegin - swift

A particular SpriteBuilder app I am developing utilises SpriteBuilder SB version 1.4.7, X Code 6.2 with iOS 8.2 iPhone deployment and func
ccPhysicsCollisionBegin(pair: ...) -> Bool { return true }.
The app runs perfectly on the iPhone 5S and iPhone 6 simulators but terminates at the above function when I use an iPhone 5, iPhone 4S or iPad 2 simulator and also when I try to load it on my 5th generation iTouch.
The error message I get is
'NSInternalInconsistencyException' reason: 'CCPhysicsCollisionBegin
delegate methods must return a BOOL.'
Can anyone advise me why this might be?

You can also call the function and return an ObjCBool instead.
For example:
ccPhysicsCollisionBegin(pair: ...) -> ObjCBool{ return true }

I just had the same issue and I found some hotfix for this to change in the Cocos Code. Seems it's a bug in CCPhysicsNode.m due to the differences between Objective-C (BOOL) and Swift (Bool). Until they fix the bug, replace the condition with:
NSAssert((strcmp(returnType, #encode(BOOL)) == 0 || strcmp(returnType, "B") == 0), #"CCPhysicsCollisionBegin delegate methods must return a BOOL.");
Hope this helps someone.

Related

Do Swift-based applications work on OS X 10.9/iOS 7 and lower?

Will Swift-based applications work on OS X 10.9 (Mavericks)/iOS 7 and lower?
For example, I have a machine running OS X 10.8 (Mountain Lion), and I am wondering if an application I write in Swift will run on it.
Or what should I have to create a Swift application using Mac OS?
I just tested it for you, Swift applications compile into standard binaries and can be run on OS X 10.9 and iOS 7.
Simple Swift application used for testing:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
var controller = UIViewController()
var view = UIView(frame: CGRectMake(0, 0, 320, 568))
view.backgroundColor = UIColor.redColor()
controller.view = view
var label = UILabel(frame: CGRectMake(0, 0, 200, 21))
label.center = CGPointMake(160, 284)
label.textAlignment = NSTextAlignment.Center
label.text = "I'am a test label"
controller.view.addSubview(label)
self.window!.rootViewController = controller
self.window!.makeKeyAndVisible()
return true
}
Swift code can be deployed to OS X 10.9 and iOS 7.0. It will usually crash at launch on older OS versions.
Apple has announced that Swift apps will be backward compatible with iOS 7 and OS X Mavericks. The WWDC app is written in Swift.
Update - As per Xcode 6 Beta 4
iOS 7 and OS X 10.9 minimum deployment target
The Swift compiler and Xcode now enforce a minimum deployment target of iOS 7 or OS X
Mavericks. Setting an earlier deployment target results in a build failure.
From Xcode 6 release note
So my previous answer(Shown below) will not be applicable to any further development. Swift will no longer available for iOS6 and below
A Swift application can be run on iOS 6. Even though many people are saying that Swift will support only iOS 7+ and OS X 10.9+, from my experience it's not.
I have tested a simple application written completely in Swift in an iOS 6 device. It works perfectly fine. As Apple says, Swift code is binary compatible with Objective-C code. It uses the same compiler and runtime to create the binary.
Here is the code I have tested:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton.buttonWithType(UIButtonType.System) as UIButton
button.frame = CGRectMake(100, 100, 100, 50)
button.backgroundColor = UIColor.greenColor()
button.setTitle("Test Button", forState: UIControlState.Normal)
button.addTarget(self, action: "buttonTapped:", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(button)
}
func buttonTapped(sender: UIButton!) {
println("buttonTapped")
}
}
It is a simple application, just adding a button programmatically. My application contains only two files, AppDelegate.swift and ViewController.swift.
So if you are not using any new APIs added as part of the iOS 8 SDK or some Swift specific APIs (corresponding API is not available for Objective-C) your application will seamlessly work on iOS 6 or later (tested and working), even on iOS 5 (not tested). Most of the APIs in Swift are just the replacement of the existing Objective-C APIs. In fact they are the same in binary.
Note: As per Xcode 6 beta 4 for swift apps deployment target should be iOS 7 or OS X 10.9(see the above update). So swift will no longer available for iOS6 and below
In brief:
Swift based applications can target back to OS X Mavericks or iOS 7 with that same app.
How is it possible ?
Xcode embeds a small Swift runtime library within your app’s bundle. Because the library is embedded, your app uses a consistent version of Swift that runs on past, present, and future OS releases.
Why should I trust this answer ?
Because I am not saying this answer as one apple guy told me in twitter or I wrote hello world and tested it.
I took it from apple developer blog.
so you can trust this.
Swift uses the same runtime as Objective-C and can even live side-by-side Objective-C in the same application (as per the WWDC 2014 keynote).
This will need to be checked/verified using Xcode 6 and the new SDK to find a final answer.
I read all answers that said: No, Swift does not work with less than iOS 7. But I said YES, I just created a Swift project that does run in Xcode 5 with 6.0 deployment target.
I just create a demo project in Xcode 6 BETA with the Swift programming language selected.
Close Xcode 6 beta, and I open this demo project in Xcode 5 with deployment target 6.0
And also select simulator 6.1.
Then that project runs well in simulator 6.1. My MacOS X is 10.9.3, so I said yes, that runs in lower than iOS 7. with 10.9.3 Mac OS X.
Here it is a screenshot of the simulator:
Here is a demo as well
While code confirms it, Apple itself has said that Swift will be compatible on iOS 7 and Mavericks in their technical keynote (State of the platforms, session 102, around the 34 min 00 sec mark) at WWDC 2014.
Swift applications are supported on iOS 7 and above as stated in Beta 4 release notes. iOS 6.0, 6.1, 7.0, 7.1, 8.0 in Xcode 6 Beta
Swift applications are supported on platforms OS X 10.9 and above. OS X 10.4 to 10.10 in Deployment Target. I have tested on targeting 10.5 to 10.10, and running on 10.9.3
It appears Swift applications don't run on OS X 10.7. I just created a simple GUI application (a view, a lable, a button) which runs fine on Mavericks. The base SDK is set to 10.9 and the deployment target to 10.7. I copied that application from the DerivedData folder over to my 10.7 virtual machine, and it crashs when starting, show this error:
Crashed Thread: 0
Exception Type: EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000002, 0x0000000000000000
Application Specific Information:
dyld: launch, loading dependent libraries
Dyld Error Message:
Library not loaded: /System/Library/Frameworks/CoreGraphics.framework/Versions/A/CoreGraphics
Referenced from: /Users/USER/Desktop/Swift-Test.app/Contents/MacOS/../Frameworks/libswiftAppKit.dylib
Reason: image not found
Binary Images:
0x109c65000 - 0x109c6afff +private.Swift-Test (1.0 - 1) <649695D0-58FD-3D02-9176-2D40D4E711F2> /Users/USER/Desktop/Swift-Test.app/Contents/MacOS/Swift-Test
0x109c83000 - 0x109dbffff +libswift_stdlib_core.dylib (1.0 - 600.0.34.4.5) <10AAC369-9404-321D-A892-49F65856D7AF> /Users/USER/Desktop/Swift-Test.app/Contents/Frameworks/libswift_stdlib_core.dylib
...
However this message is irritating, since there's certainly a CoreGraphics library in this VM. Other applications that make heavy use of CoreGraphics work just fine.
This is the post I read from apple Swift blog, might be helpful:
App Compatibility:
If you write a Swift app you can trust that your app will work well into the future. In fact, you can target back to OS X Mavericks or iOS 7 with that same app. This is possible because Xcode embeds a small Swift runtime library within your app's bundle. Because the library is embedded, your app uses a consistent version of Swift that runs on past, present, and future OS releases.
Binary Compatibility and Frameworks:
While your app's runtime compatibility is ensured, the Swift language itself will continue to evolve, and the binary interface will also change. To be safe, all components of your app should be built with the same version of Xcode and the Swift compiler to ensure that they work together.
This means that frameworks need to be managed carefully. For instance, if your project uses frameworks to share code with an embedded extension, you will want to build the frameworks, app, and extensions together. It would be dangerous to rely upon binary frameworks that use Swift — especially from third parties. As Swift changes, those frameworks will be incompatible with the rest of your app. When the binary interface stabilizes in a year or two, the Swift runtime will become part of the host OS and this limitation will no longer exist.
I tested running a bare-bone, Swift-based app on an iPod Touch (3rd gen) device. It appears Swift-based apps don't work with iOS 5.x but do work with iOS 6.x.
Here's what shows up in the debug log when I tried to launch the test app with iOS 5.0.1:
dyld: F_ADDFILESIGS failed for /private/var/mobile/Applications/59E31E79-9525-43B0-9DF6-8FEF3C0080F1/SwiftTestApp.app/Frameworks/libswift_stdlib_core.dylib with errno=1
dyld: F_ADDFILESIGS failed for /private/var/mobile/Applications/59E31E79-9525-43B0-9DF6-8FEF3C0080F1/SwiftTestApp.app/Frameworks/libswiftCoreGraphics.dylib with errno=1
dyld: F_ADDFILESIGS failed for /private/var/mobile/Applications/59E31E79-9525-43B0-9DF6-8FEF3C0080F1/SwiftTestApp.app/Frameworks/libswiftDarwin.dylib with errno=1
dyld: F_ADDFILESIGS failed for /private/var/mobile/Applications/59E31E79-9525-43B0-9DF6-8FEF3C0080F1/SwiftTestApp.app/Frameworks/libswiftDispatch.dylib with errno=1
dyld: F_ADDFILESIGS failed for /private/var/mobile/Applications/59E31E79-9525-43B0-9DF6-8FEF3C0080F1/SwiftTestApp.app/Frameworks/libswiftFoundation.dylib with errno=1
dyld: F_ADDFILESIGS failed for /private/var/mobile/Applications/59E31E79-9525-43B0-9DF6-8FEF3C0080F1/SwiftTestApp.app/Frameworks/libswiftObjectiveC.dylib with errno=1
dyld: F_ADDFILESIGS failed for /private/var/mobile/Applications/59E31E79-9525-43B0-9DF6-8FEF3C0080F1/SwiftTestApp.app/Frameworks/libswiftUIKit.dylib with errno=1
dyld: Symbol not found: _OBJC_CLASS_$_NSObject
Referenced from: /private/var/mobile/Applications/59E31E79-9525-43B0-9DF6-8FEF3C0080F1/SwiftTestApp.app/Frameworks/libswift_stdlib_core.dylib
Expected in: /usr/lib/libobjc.A.dylib
in /private/var/mobile/Applications/59E31E79-9525-43B0-9DF6-8FEF3C0080F1/SwiftTestApp.app/Frameworks/libswift_stdlib_core.dylib
For iOS 6.1.6, the app runs fine without displaying those error messages.
There seems to be a lot of old answers here so I just wanted to post the official response from the Swift team. Swift is backwards compatible with OS X Mavericks and iOS 7
Apple developer swift blog : Objective-C id as Swift Any
Jul 11, 2014
Compatibility
One of the most common questions we heard at WWDC was, “What is the compatibility story for Swift?”. This seems like a great first topic.
App Compatibility
Simply put, if you write a Swift app today and submit it to the App Store this Fall when iOS 8 and OS X Yosemite are released, you can trust that your app will work well into the future. In fact, you can target back to OS X Mavericks or iOS 7 with that same app. This is possible because Xcode embeds a small Swift runtime library within your app’s bundle. Because the library is embedded, your app uses a consistent version of Swift that runs on past, present, and future OS releases.
I also tried a very simple app on 10.8 (one button, sets text on a label). It crashed at startup, as Greg Parker stated:
Dyld Error Message:
Symbol not found: __dispatch_source_type_memorypressure
Referenced from: /Volumes/*/SwifTest.app/Contents/MacOS/../Frameworks/libswiftDispatch.dylib
Expected in: /usr/lib/libSystem.B.dylib
in /Volumes/*/SwifTest.app/Contents/MacOS/../Frameworks/libswiftDispatch.dylib
(This was using a deployment target of 10.7)
Try the following code:
It's working without StoryBoard:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
self.window!.backgroundColor = UIColor.whiteColor()
// Create a nav/vc pair using the custom ViewController class
let nav = UINavigationController()
let vc = ViewController(nibName: "ViewController", bundle: nil)
// Push the vc onto the nav
nav.pushViewController(vc, animated: false)
// Set the window’s root view controller
self.window!.rootViewController = nav
// Present the window
self.window!.makeKeyAndVisible()
return true
}
Yes, in fact Apple has announced that Swift apps will be backward compatible with iOS 7 and OS X Mavericks. Furthermore the WWDC app is written in the Swift programming language.
When it comes to Swift Frameworks.
As for today, with Xcode version 6.1.1 (6A2008a), if the Swift framework is targeted to iOS 7.1, linker report warning
ld: warning: embedded dylibs/frameworks only run on iOS 8 or later.
and application can't be submitted to AppStore. Check this issue : Lint to prevent dynamic libraries and frameworks from passing with iOS 7
Quick Update, effective from February 15th, 2015, we cannot submit apps to the store that were developed using an SDK prior to iOS 8. So, keeping that in mind , its better to not to worry about this issue as many people have suggested that apps made in Swift can be deployed to OS X 10.9 and iOS 7.0 as well.
Answered code-snippet posted by Leandros seems bit old. I have fixed and made it compilable in Swift 5.
Swift 5
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
let controller = UIViewController()
let view = UIView(frame: CGRect(x: 0, y: 0, width: 320, height: 568))
view.backgroundColor = UIColor.red
controller.view = view
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 21))
label.center = CGPoint(x: 160, y: 284)
label.textAlignment = NSTextAlignment.center
label.text = "I'am a test label"
controller.view.addSubview(label)
self.window!.rootViewController = controller
self.window!.makeKeyAndVisible()
return true
}

Adapt app from iOS7 to iOS6

I wrote my application for iPhone in xcode 5.0 and it supports only 7 ios.
How can I make it available for ios 6?
Also interested in how to prevent applications load on ipad?
First question: Make sure your deployment target is 6.0, don't use API's that are iOS 7 only, or check by using
if ([someObject respondsToSelector:#selector(ios7onlymethod)] {
// do your iOS 7 only stuff
} else {
// Fall back to iOS 6-supported ways
}
Or use
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0f) {
// do your iOS 7 only stuff
} else {
// Fall back to iOS 6-supported ways
}
New frameworks you want to use should be marked as optional in Xcode; to do that select your target, click general, and scroll to the "Linked Frameworks and Libraries" section.
What's really cool is that classes in frameworks marked as optional are replaced with nil on versions of iOS that don't have them. So suppose you write some code like this, using a class from the Sprite Kit framework, new in iOS 7:
SKSpriteNode *spriteNode = [SKSpriteNode spriteWithImageNamed:#"mySprite"];
On iOS 6, when the linker, which "links" frameworks to apps (apps don't copy frameworks, they just get them from the system), sees SKSpriteNode in your code, and the framework is marked as optional, that line of code will be replaced by this:
... = [nil spriteWithImageNamed:#"mySprite"];
Sending messages to nil in Objective-C does absolutely nothing, so the above code doesn't crash. No problem. So instead of lingering your code with if-statements checking for the existence of a class, you can just go with the flow and let the dynamic linker do the work.
Further reading:
iOS 7 UI Transition Guide: Supporting iOS 6
Supporting Multiple iOS Versions and Devices
Second question: There is no way to say that you want your app to only run on iPhones and iPod touches. You can require things that are specifical to the iPhone and iPod touch (like a certain processor architecture or the M7 motion coprocessor) but Apple won't like it if you require the M7 chip to exclude a certain device when you don't even need it. You should probably think about why you don't want your app to run on iPads.

UITableView of iOS SDK 6.1 don't compatible with iOS SDK 5.1

I have created UITableView project in XCode 4.6 with iOS 6.1 SDK, and set target sdk to 5.1, when the app calling dequeueReusableCellWithIdentifier in cellForRowAtIndexPath function, the app throw a exception, the simulator is 5.1, on simulator 6.x is ok.
1:
[UITableView dequeueReusableCellWithIdentifier:forIndexPath:]: unrecognized selector sent to instance
2:Terminating app due to uncaught exception NSInvalidArgumentException, reason: -[UITableView dequeueReusableCellWithIdentifier:forIndexPath:]: unrecognized selector sent to instance
1. dequeueReusableHeaderFooterViewWithIdentifier
Availability
Available in iOS 2.0 and later.
-> Minimum iOS version required to run this function is iOS 2.0
2 .dequeueReusableCellWithIdentifier:forIndexPath:
Availability
Available in iOS 6.0 and later.
-> Minimum iOS version required to run this function is iOS 6.0
EDIT
IF your want to use this function the you can check your current device version and then implement this
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
NSLog(#"curr version = %f",[currSysVer floatValue]);
if ([currSysVer floatValue] >= 6) {
//iOS 6.0 and later code
// dequeueReusableCellWithIdentifier:forIndexPath:
}
else{
//dequeueReusableHeaderFooterViewWithIdentifier
}
If you look at the Apple documentation, you'll see that dequeueReusableCellWithIdentifier: forIndexPath: came in with iOS 6.0.
That means if you try to call this method on iOS 5.X devices, it's going to throw an exception.
It would be better if you used the older "dequeueReusableCellWithIdentifier:" call if possible.
One big difference between the two calls is that the latter (older) one can return nil, in which case you need to alloc/init a new reuseable cell.

ios: add printing, but keep compatibility with ios 3

i'm trying to add printing features to an ios app.
while printing itself works fine, and the app works on ios > 4, i haven't figured out yet how to keep the ios 3.1 compatibility...
i guess the issue is this: completionHandler:(UIPrintInteractionCompletionHandler)
A block of type UIPrintInteractionCompletionHandler that you implement to handle the
conclusion of the print job (for instance, to reset state) and to
handle any errors encountered in printing.
once i add the block:
void (^completionHandler)(UIPrintInteractionController *, BOOL, NSError *) =
^(UIPrintInteractionController *printController, BOOL completed, NSError *error) {
};
the app won't even launch on iOS 3.1
probably because blocks aren't available there.
yes, i made sure that this code won't be run when launched on iOS 3.1...
if (([[[UIDevice currentDevice] systemVersion] floatValue] >= 4.2) && ([UIPrintInteractionController isPrintingAvailable]))
so i wonder if there's a way to have printing support for iOS >4.2, but keeping it to run on iOS 3.1?
maybe there's a way to use a method instead of the "block"?
or how would be the correct way to have printing available on supported iOS devices, and remain backwards compatible to iOS 3.1?
just add -weak_framework UIKit to the project settings under "Other Linker Flags" and make sure you use conditional code for printing API.
Conditional code should check feature availability, not OS version:
if (NSClassFromString(#"UIPrintInteractionController")){
void (^completionHandler)(UIPrintInteractionController *, BOOL, NSError *) =
^(UIPrintInteractionController *printController, BOOL completed, NSError *error) {
};
}
Set your project target to iOS 3, and you're good to go.
The best practice for detecting if AirPrint is available is to use NSClassFromString. If you use this method in general, then you always know if exactly the class you want is available, without having to hard-code which features correspond with which version. Example code:
Class printControllerClass = NSClassFromString(#"UIPrintInteractionController");
if (printControllerClass) {
[self setupCanPrintUI];
} else {
[self setupCannotPrintUI];
}
That way your app can still work on previous iOS versions, although it won't be able to print from them.
I've been able to use this technique and run it on an iOS 3.0 device without any problems with the block code (the ^-based stuff). In my build settings, I have the Base SDK set to iOS 4.2, and the Deployment Target set to iOS 3.0.
I posted a sample Xcode project at the end of this blog post on printing in iOS. This is the project that successfully runs for me on a device with iOS 3.0 and another device with iOS 4.2. You may have to change the bundle identifier in the info.plist to get the code-signing to work for you, but that's independent of the printing stuff.
Set Deployment Target in your Project Settings to iOS 3.x. However, set the Base SDK to 4.2. Now you can use the 4.2 classes and iPhones running 3.x can install your app too.
Keep in mind that when you use a 4.2 class on an iPhone 3.x, the application will crash (so keep checking the system version on-the-go).
NSComparisonResult order = [[UIDevice currentDevice].systemVersion compare:#"3.2" options: NSNumericSearch];
if (order == NSOrderedSame || order == NSOrderedDescending && [[UIDevice currentDevice]isMultitaskingSupported]) {
// >4.2
}
else {
//< 4.2
}
Note:
also change UIKit framework setting from "required" to "weak" this will help you to run application on iOs < 4.2 as well as iOs >= 4.2

How do I run a universal app on the iPhone 3.1.3 simulator?

I'm working on a new app that I want to be universal for the iPhone and iPad. I started out with the "Create a Window-based app" wizard, and it created separate app delegates in "iPhone" and "iPad" groups. Since I already was quite familiar with iPhone dev, I did that part of my project, and now I'm ready to do some iPad stuff.
So... I started out by adding a UISplitViewController to my iPad delegate, switch the Active SDK to 3.2, and it works! But when I switch back to 3.1.3, and try to run it in the simulator, Build and Go fails. For starters, I see:
...path.../iPad/AppDelegate_Pad.h:13: error: expected specifier-qualifier-list before 'UISplitViewController'
I've got my Base SDK set to 3.2 and my Deployment Target set to 3.1.3. I thought that was enough. But I also have found in the documentation this method to conditionally compile:
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 30200
MyIPadViewController* vc;
// Create the iPad view controller
#else
MyIPhoneViewController* vc;
// Create the iPhone view controller
#endif
So do I need to do this everywhere? It seems like an awful lot of code to add (that I'll be getting rid of in a short time for 4.0 anyway) so I feel like I must be doing something wrong. And, I don't even have any idea how this works for things like #property or #synthesize declarations.
tl;dr version of the question - did I miss a setting somewhere?
I use this C function to help keep the code concise:
BOOL isPad() {
return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
}
Another thing I do, when I have different xib files for iPhone vs iPad. I have a stripPadSuffixOnPhone() function that helps keep the code simpler:
// Load/create the Delete table cell with delete button
self.deleteCell = [Utilities loadNib:stripPadSuffixOnPhone(#"DeleteCell~ipad")
ClassName:#"DeleteCell"
Owner:self];
Things like that can make coding more straightforward and a lot less conditionals. Still have to test everything twice though.
Quite the opposite. A universal app runs the same binary on iPhone and iPad so you cannot use conditional compilation to differentiate between the two version. But you need to use the macro Apple cites in the documentation:
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
// iPad-specific code
} else {
// iPhone-specific code
}
Here's what works for me:
Build your app using SDK 3.2.
Switch the active SDK to iPhone Simulator 3.1.3 (or whatever).
From the Run menu select Debug (not Build and Debug).
The binary built under 3.2 will be installed in the 3.x simulator without rebuilding. When you are finished don't forget to set your active SDK back to 3.2.