I solved the problem. I control-clicked on the archive in the organizer window to show it in the finder. It’s a .xarchive bundle. Control clicking on it shows a pop-up menu with the option to show the package contents. the package contains three things: a dSYMs folder, an Info.plist and a Products folder. The Products folder contains an Applications folder. This folder has a copy of the application and an app name.docarchive. Double clicking on the .docarchive opens the developer documentation with my application shown in the left side bar and a list of the Swift classes and functions that I implemented in my Objective-C application. So this looks like something that Xcode did when I added swift objects to the app with a bridging header. When there’s a .docarchive in the Application’s folder Xcode thinks it’s an type other.
Setting the target build setting in Document Compiler - Options > Build Documentation During ‘Build’ to no fixes the problem.
Post
Replies
Boosts
Views
Activity
I solved the problem. I control-clicked on the archive in the organizer window to show it in the finder. It’s a .xarchive bundle. Control clicking on it shows a pop-up menu with the option to show the package contents. the package contains three things: a dSYMs folder, an Info.plist and a Products folder. The Products folder contains an Applications folder. This folder has a copy of the application and an appname.docarchive. Double clicking on the .docarchive opens the developer documentation with my application shown in the left side bar and a list of the Swift classes and functions that I implemented in my Objective-C application. So this looks like something that Xcode did when I added swift objects to the Objective-C app with a bridging header. When there’s a .docarchive in the Application folder Xcode thinks it’s an type other.
Setting the target build setting in Document Compiler - Options > Build Documentation During ‘Build’ to NO- fixes the problem.
Today I archived my project and exported it as an app, so I could use it on my machine. Then I set the appname>build to any Mac so I could upload it to the App Store. It started to archive it as other items. I literally didn't change anything except to build it for Intel and Apple silicon. I have been archiving the app for years with the same project settings - I didn't change anything. I have carefully studied your advice and the articles you cite about this and none of the suggestions on these have helped. This sure looks like an XCode bug to me.
Quinn, no the Applications folder contains the app and a file named appname.docarchive. Ok so this is wrong but what can i do to fix it?
Today I archived my project and exported it as an app, so I could use it on my machine. Then I set the appname>build to any Mac so I could upload it to the App Store. It started to archive it as other items. I literally didn't change anything except to build in for Intel and Apple silicon. I have been archiving the app for years with the same project settings - I didn't change anything. I have carefully studied the threads about this and none of the suggestions on these have helped. This sure looks like an XCode bug to me.
I solved the problem like this:
In my AppController’s init method I added an observer to receive an
NSApplicationWillFinishLaunchingNotification
to remove the extra menu items. This won’t work. Xcode adds the extra items after this. You have to add a selector that will be notified by the
NSApplicationDidFinishLaunchingNotification.
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver: self selector: @selector(handleAppLaunched:) name: @"NSApplicationDidFinishLaunchingNotification" object: nil];
The method to remove the extra menus looks like this:
- (void) handleAppLaunched: (NSNotification *) note
{
NSMenu* edit = [[[[NSApplication sharedApplication] mainMenu] itemWithTitle: @"Edit"] submenu];
while( [[[edit itemAtIndex: [edit numberOfItems] - 1] title] compare: @"Paste" ] != 0) //-1 for zero indexing
[edit removeItemAtIndex: [edit numberOfItems] -1]; //decrements the number of Items
}
The undocumented API for removing these with the user defaults is a cleaner way to do this.
It’s pretty ridiculous that there are un-documented APIs and that there is no straight forward way to do this, like a build setting or object method, since this is something you would want to do for a lot of applications.
This is still broken FIVE YEARS later.
Thank you so much for your help. I haven't decided what version to target, but this is easy. The fact that my project has a valid receipt that I got by calling exit(173) made it easier. In my opinion deprecating this is a bad idea that will make it harder for developers.
Thank you so much. Theoretically I could return status from the block but this won't work in this case. I could also do something like post a notification. Does the Swift function have to be async?
I was working on this today and I encountered more strange problems:
Even though the chekReceipt() Swift function returns a String (-> String), the MyAppTransaction class method in the automatically generated name-Swift.h file is defined as (void). This won’t work because if the verificationResult is either .unverified or there is an error I need to post an alert. You can only post an alert from the main thread. Calling one from the completion handler will cause a crash. I have to return a result to the main thread to create an alert. I tried to edit the name-Swift.h header to change the return type of the checkReceiptWithCompletionHandler method to string but I can’t, it’s apparently read only.
Within the scope of the completion handler you can use the status string, for example NSLog(@"status: %@", status);, but you can’t return it to the calling function. I was hoping to copy it to the calling function with something like this:
NSString* verifyWithStoreKit(void)
{
NSString* myString;
[MyAppTransaction checkReceiptWithCompletionHandler: ^(NSString * _Nonnull status)
{
myString = [[NSString string] initWithString: status];
}];
//@autoreleasepool {
// Setup code that might create autoreleased objects goes here.
//}
return myString;
}
But Xcode won’t build instructions like this or myString is nil. What can I do?
endecotp: the syntax that surprised be was:
[MyAppTransaction checkReceiptWithCompletionHandler:^(NSString * _Nonnull status) {
NSLog(@"status: %@", status);
}];
I'm not having a problem with it but I never saw it until it was posted here. Also I don't know how Swift types map to Objective-C types. Quinn mentioned that String is equivalent to NSString. This makes sense but it would be useful if all of this was documented somewhere.
It would be helpful if I could read the name-Swift.h header to see how to invoke the Swift object methods. The project runs with this invisible header included but it isn't visible in my project hierarchy, Find can't find it, Spotlight can't find it, Open Quickly can't find it and XCode -> Find can't find it. This is extremely unhelpful.
I got this to work and this is REALLY WEIRD:
If I #import the name-Swift.h header in a .m file the project will build and I can use the MyAppTransaction object in my .m files.
BUT XCode doesn't actually create the file in my project directories. Apparently it's cryptic, invisible, implied or something. It would have saved me a huge amount of trouble if the developer documentation described this or if someone mentioned it.
Also I never would have guessed that you would have to invoke the method using that syntax. Are a lot of the calls to Swift objects as weird as that? Is there some documentation about this?
Update: I spoke too soon. This will work in my test project but not on a major project for a Mac App on the App Store. Something in the build settings?
I already have a test project. I also created a test project App->objective-C. With both of these when I add the receipt validation Swift file to the projects XCode asks me if I want to create a bridging header. It creates the name-Bridging-header.h.
This is not the bridging head I want. I want the name-Swift.h header. The name-bridging-headers are empty.
Shouldn't they at least have this:
#ifndef name_Bridging_Header_h
#define name_Bridging_Header_h
#endif /* name_Bridging_Header_h */
So XCode doesn't create the bridging header. Is there something missing in the build settings or something?
Update: things have gone from bad to worse. I removed the Swift files from both projects, build them and when I add the Swift file it adds it to the projects but doesn't ask to create a bridging header.
Update 2: If I delete the Swift files, clean and rebuild my test project and add the Swift File, XCode will automatically create the two bridging headers. They will have the #ifndef, #define #endifs in them but no Objective-C prototype in the name-Swift.h header for the Swift Function to verify receipts.
The name-Swift.h header was filled in by XCode:
#ifndef Chac_Swift_h
#define Chac_Swift_h
#endif /* Chac_Swift_h */
The Swift object.swift file:
import StoreKit
@objc
class MyAppTransaction: NSObject {
@objc
class func checkReceipt() async -> String {
do {
let verificationResult = try await AppTransaction.shared
switch verificationResult {
case .unverified(_, _):
return "NG"
case .verified(_):
return "OK"
}
} catch {
return "ERR"
}
}
}
This will build if my target is at least 10.13 but there's no prototype in the name-Swift.h file. I thought that XCode was supposed to create this?
Calling [MyAppTransaction checkReceipt] from a .m file will result in an error - Class method +checkReceipt not found. Theoretically something in the -Swift.h file like:
@interface MyAppTransaction : NSObject
- (NSString*)checkReceipt;
@end
Should allow XCode to recognize the Class method, but what?