Hi
I am using SDK 4.1 to build an iPhone app and I set the target OS to 3.1.3.
When I install the app on devices running iOS4.1. everything goes smoothly.
When I try to run the app on devices running 3.1.3 I get the stacktrace below.
dyld: Symbol not found: _OBJC_CLASS_$_UINib
Referenced from: /var/mobile/Applications/BDD67A1E-9B40-43E7-A012-7D92036B2E24/ThisIsMy.app/ThisIsMy
Expected in: /System/Library/Frameworks/UIKit.framework/UIKit
in /var/mobile/Applications/BDD67A1E-9B40-43E7-A012-7D92036B2E24/ThisIsMy.app/ThisIsMy
My guess is that it's because UINib was only added to the SDK in 4.0.
What I would like to know is how you mitigate this problem. What should I do to support 3.1.3?
Cheers..
I strongly recommend you not weakly link UIKit. This may hide future linker issues and result in crashes. I'm also simply not comfortable with telling the linker that UIKit is optional when it plainly isn't. Big hack.
Instead, initialize and call UIPopoverController indirectly using NSClassFromString:
Class popover = NSClassFromString(#"UIPopoverController");
if (nil != popover)
{
self.myPopover = [[popover alloc] initWithContentViewController:myContent];
}
If you still have linker errors, you may need to call UIPopoverController's messages using NSSelectorFromString:
Class popover = NSClassFromString(#"UIPopoverController");
if (nil != popover)
{
SEL myInit = NSSelectorFromString(#"initWithContentViewController:");
self.myPopover = [[popover alloc] performSelector:myInit withObject:myContent];
}
For portability, I recommend writing a proxy object to handle these implementation details.
First, you need to change the framework reference to a weak link (aka "optional"). Then use the techniques described here to test that a class exists before calling your code that uses it.
Related
Just hit a problem where I need to work with a external framework and bundle.
While the frame is imported and its functions can be called just fine, one of it's methods tries to load a nib from the accompanying bundle, which ends in a NSInternalInconsistencyException for the reason
"Could not load NIB in bundle".
I noticed that while the bundle is in the Copy Bundle Resources and can be found by calling Bundle.allBundles, the error message says the bundle is "not yet loaded". Is there something I was supposed to do so the bundle could be loaded beforehand?
Update: I did not provide the related code earlier because the error happened as a colateral effect of a framework call, so I don't know exactly how the nib is "loaded".
The code itself is this:
if let request = AUTRequest.init(transactionType: .debitGeneric) {
AUTCTFClient.executeTransaction(with: request, from: self) { (_response) in
if let response = _response {
print(response)
}
}
}
self is the current viewcontroller and the error happens after the executeTransaction call but before the response block execution.
Is this somehow related to the Bundle not being loaded or is the framework at fault himself?
If you are using code do load the nib, you need to make sure you are loading it from the correct bundle:
let bundle = Bundle(for: ClassName.self)
let view = bundle.loadNibNamed("nib_name", owner: nil, options: nil)![0]
If you are using storyboard, please make sure to select to correct Module (the framework). You can select module in the Identity Inspector (in interface builder press cmd+alt+3).
After trying to find solutions for a while, the most obvious answer is that the framework in question was compiled with missing files, that the "AUTCTFClient.executeTransaction" tries to call in its execution. This point is "confirmed" by older versions of the framework showing some kind of progress view on execution. (but sadly they were not usable in our case)
If you somehow got this problem, it'll probably be best to ask the owners(or search) for an updated or stable version of their framework.
In my Swift 2 project, targeting iOS 9.2 and above, in Xcode 8.2.1, I have code that shows the mail-compose screen like so:
if MFMailComposeViewController.canSendMail() {
let composeMailVC = MFMailComposeViewController()
composeMailVC.mailComposeDelegate = self
composeMailVC.setSubject("Test")
// etc
}
Originally I had a reference to the MessageUI.framework in my project properties, but after removing the framework reference and cleaning the project, it still builds fine and when I run the code on my device the mail compose window still appears and seems fully functional.
I cannot find any explicit references to MessageUI.framework in the raw text of my .xcodeproj file, nor is there anything in my Objective-C bridging header.
I know that Swift does make some implicit framework references, but I couldn't find anything that suggests MessageUI.framework is one of them.
Curiously when I jump to the definition of MFMailComposeViewController XCode shows it in the MessageUI module.
The compiler automatically added the frame work in given its previous direction - IE. Import.
So I am attempting to bring the iOS 5 SDK to the Theos Makefile system. I have the following things working: Private Frameworks, Multitasking from UIKit. Since Theos uses SDK 3. This jump to SDK 5 breaks a few methods as they're deprecated. Keep in mind that I'll be using RPetrich's headers on GitHub for this. With that in mind, I'm trying to add the following dismissal code to the UIViewController header.
- (void)dismissViewControllerAnimated: (BOOL)flag completion: (void (^)(void))completion __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_5_0);
This makes my compiler complain about the (void (^) (void)) part. I've tried replacing it with BOOL and just a regular void and then just calling nil when using the method. Doesn't work that way. I wanted to know if there was a way I can successfully compile with this method, or if I can somehow use dismissModalViewControllerAnimated: again. Some reason I can still use presentModalViewController:animated: and it says they both WILL be deprecated. Any suggestions?
change default compiler gcc/g++ to apple's clang/clang++
I am writing an app for my iPad running 3.2.2 with XCode 3.2.3. It seems that the highest version of the iOS for iPad this version of XCode has is 3.2, but other apps load fine onto the phone so this doesn't seem to be an issue. I am attempting to make use of the new UITextChecker class. I have imported UIKit, and UITextChecker.h appears in the headers folder under the UIKit.framework icon. However, when I try to compile this code:
NSString *theLanguage = [[UITextChecker availableLanguages] objectAtIndex:0];
or simply this:
UITextChecker *textChecker;
XCode tells me that UITextChecker is undeclared. Any ideas what it going on here? Thanks!
James
Here is a picture of the UIViewController's header file:
For whatever reason, UIKit.h does not import UITextChecker.h. You can fix this by also adding the following line.
#import <UIKit/UITextChecker.h>
well to begin with I'm sure this is a simple question.
I am developing an iPhone app with the iAd Framework, which only runs for iOS 4.0 or higher.
Still, I wanna choose a iPhone OS 3.0 deployment target, which causes everything to crash.
How do I conditionally include the iAd framework?
...I mean, it would be something like:
...if([[UIDevice currentDevice] systemVersion]>=4.0]) #import
Obviously this won't work because I don't know the correct syntax. Also:
How do I conditionally declare an AdView* variable?
How do I conditionally handle this AdView* variable in my implementation file.
If you guys could help me, I will be very well impressed.
Thanks
You don't need to change your include, you need to make the iAd (or any other new framework) linked weakly:
In your target, find iAd in the linked frameworks and change its "Role" from "Required" to "Weak".
To handle the variable conditionally, use NSClassFromString function, like this:
Class AdClass = NSClassFromString(#"ADBannerView");
if(AdClass) {//if the class exists
ADBannerView* myAd = [[AdClass alloc] initWithFrame:CGRectZero];
// do something with the ad
}
If OS is older than iOS 4.0, AdClass will be nil and the code won't execute. Note that using ADBannerView* as the type of the variable shouldn't cause any problems, as it's just a hint for a compiler and is the same as id after compilation.