NSMutableAttributedString on iOS 3.1.3 - iphone

I'm dealing with a very odd situation. I'm implementing Attributed Strings into my iOS application, and I had the warning going in that they are available iOS 3.2 and above. Because I still support 3.1.3 on iPhones, I knew I had to weakly link CoreText and probably so some compile time OS check before using them.
I weakly linked the framework, but out of curiosity I just used the class as is and ran it on a 3.1.3 device... and it works. What am I missing here, I'm so confused why this isn't crashing. I'm 100% sure this is a 3.1.3 device, but is NSMutableAttributedString a hidden class on 3.1.3, and thus actually does work because of the dynamic nature of objective-c ?

I am the author of the OHAttributedLabel class.
Thanks for using it!
The behavior you have is strange, as OHAttributedLabel uses the CoreText framework to draw the NSAttributedStrings on screen.
As CoreText is only available since iOS 3.2, I can't see how it would be possible for this to work under iOS 3.2, especially iOS 3.1.3…?

Did it really work, instead of just not crashing?
Depending on the setting, a non-existent class becomes just nil. Note that in Objective-C you can send a message to a nil. Then it just returns nil or 0. Then [[NSAttibutedString alloc] init] might just return nil, without crashing.

CoreText was introduced with iOS 3.2. If you weak link against it the app will start, but it will crash on the first instance on calling a CoreText function.
To still be compatible with earlier versions you CAN weak link and avoid CT code by drawing the text with Quartz instead. You would detect if CT exists on the device and use it if yes, otherwise you would have a crude fallback mechanism for your drawing.

Related

Is SwiftUI backwards-compatible with iOS 12.x and older?

If I have an app made with SwiftUI, will it work for iOS below iOS 13?
I just checked it out in Xcode 11 and can confirm it won't be backwards-compatible, as can be seen in SwiftUI's View implementation:
/// A piece of user interface.
///
/// You create custom views by declaring types that conform to the `View`
/// protocol. Implement the required `body` property to provide the content
/// and behavior for your custom view.
#available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public protocol View : _View {
/// The type of view representing the body of this view.
///
/// When you create a custom view, Swift infers this type from your
/// implementation of the required `body` property.
associatedtype Body : View
/// Declares the content and behavior of this view.
var body: Self.Body { get }
}
SwiftUI and Combine use Opaque-Return-Types in Swift 5.1 and since Opaque-Return-Types (alongside other features) are implemented in Swift 5.1 and due to the nature of their implementation, they can not be back deployed to Swift 5.0(unlike DSL or Property-Wrappers), and because iOS 13 is the earliest iOS SDK that contains Swift 5.1 runtime in the OS, so the answer to the question is no and SwiftUI and Combine can not be used on earlier versions of iOS.
Unless, Apple provides a way to bundle Swift 5.1 runtime (or future releases) with the application like it used to do with earlier Swift versions, but since it will increase App-size and add overhead to the whole system again, I doubt this will ever happen.
It might be backward compatible
Swift 5.1 is not released yet and SwiftUI uses features such as opaque return types, DSL, propertyDelegate(introduced in WWDC as propertyWrapper) and etc, which will be available only in Swift 5.1. Since Swift 5 is binary stable, I guess it was not possible to use embedded swift-frameworks inside Xcode11, hence they’ve re-implemented these features in Cocoa’s core and marked them as iOS13+ available until Swift 5.1 gets released.
My assumptions are based on the fact that, Ordered Collection Diffing and DSL are going to be available in Swift 5.1 and have no correlations with Xcode or Apple’s eco-system, but they’re also marked as #available(iOS13,...). This means that they had to mark everything using Swift 5.1 features with the iOS availability attribute. Some of them will get removed once Swift 5.1 gets released, but we can’t be sure about SwiftUI and Combine unless Apple tells otherwise. This is also mentioned in DSL’s proposal:
Implementation: PR. Note that the implementation in the Xcode developer preview uses a somewhat simpler transformation than that described here. The linked PR reflects the implementation in the preview but is under active development to match this proposal.
So backward incompatibility limitation might be lifted when Swift 5.1 gets released, but it really needs to be clarified by Apple team.
I don't think so, because all libraries are already annotated for iOS 13 or higher.
Also, in the documentation, Apple clearly mentions the supported versions:
iOS13.0+ beta
macOS10.15+ beta
tvOS 13.0+ beta
watchOS 6.0+ beta
No. SwiftUI requires a deployment target of iOS 13 or later, macOS 10.15 or later, tvOS 13 or later, or watchOS 6 or later. The framework contains many new types that don’t exist on older versions of the OSs.
If you are shooting to support iPhone and not iPad you could probably expect most users will upgrade to iOS 13 within 12-18 months(starting with the release date). Maybe 85-90%? (I think Apple said at this point theres still 15% of people not on iOS 12) That’s still quite a while though to where you aren’t going to be able to deploy SwiftUI apps right away or else risk alienating a lot of users.
Also depending on what the other 10-15% is, that could mean a lot of users (and $$) for you left on the table.
If you are supporting iPad as well then its more tricky because people don't upgrade their iPads as often. Theres a lot of iPad 2s along with 3rd and 4th generation iPads still out in the wild, that only have 10.3.3 and cannot upgrade anymore. People just aren't going to go get up and go pay between $400 - $1,000 for a new iPad when theirs works perfectly fine.
There’s always room and a need for updating the app, making it better, fixing bugs, that don’t necessarily have anything to do with iOS 13. i.e. finding a bug you didn’t know about before that making a lot of users unhappy.. not on the latest iOS version. and we haven't even talking about enterprise / corporate customers that a lot of dev shops support. theres a lot of more pushback on iOS updates for various reasons in that area.
So before you get all excited about iOS 13 and SwiftUI (which you absolutely should because its awesome), back in the real world, outside of Silicon Valley, that's not exactly going to align with what the average consumer expects and you will need to support older devices and need to because theres just too many people you would be alienating.
It is compatible with iOS 13+. Here is link to its documentation.
https://developer.apple.com/documentation/swiftui/
Even Xcode 10 does not support it. You need to use Xcode 11 which is in beta as of (Jun 3 2019).
https://developer.apple.com/tutorials/swiftui/creating-and-combining-views
Based on Apple documentation it's available only starting with iOS 13, unfortunately.
https://developer.apple.com/documentation/swiftui/
only works for ios 13 or later
you can still attach your SwiftUI code by using
#available(iOS 13.0, *)
if you still using Xcode below Xcode 11 and have SwiftUI code, you can wrap it with
#if canImport(SwiftUI)
...
#endif
This can fix the issue when compiling with Xcode below Xcode 11
As everyone has said, it will not be backwards compatible with older iOS versions. But given that Apple consistently have a high install base of their latest iOS, and also given that iOS 13 requires iPhone 6S or later, iPad Air 2 or later, the new iPad mini 4 and iPhone SE. The vast majority of users will be able to install iOS 13 and enjoy lovely SwiftUI apps.
Sadly no, SwiftUI is only allowed in iOS 13 and above. It was introduced in the iOS 13 framework. Before iOS 13, everything was built using Obj-C framework (Including Swift).
On the right side of the dev documentation, it shows the supported versions of iOS, macOS, tvOS, watchOS, etc.
https://developer.apple.com/documentation/swiftui/
Hope this helps!
As all people before me mentioned, it's very clear that it will require iOS 13 or later. But as a new iOS developer, I was worried about to what extent I should adopt SwiftUI in comparison with UIKit. I already built some small projects with UIKit, and went somewhere advanced with it.
But as SwiftUI commenced, how to combine between them. The article in the following link puts all in context:
https://www.hackingwithswift.com/quick-start/swiftui/answering-the-big-question-should-you-learn-swiftui-uikit-or-both
My only concern now is that I noticed with Xcode 11 that an Xcode project cannot combine both Storyboards and SwiftUI.
Create two storyboards, one with UIKit, and the other using UIHostingController with SwiftUI.
Then use if #available() to check if the OS supports SwiftUI.
// SwiftUI
let storyboard_swiftUI = UIStoryboard(name: "Main-SwiftUI", bundle: nil)
let controller_swiftUI = storyboard_swiftUI.instantiateViewController(withIdentifier: "ViewControllerSwiftUI")
// UIKit
let storyboard_UIKit = UIStoryboard(name: "Main-UIKit", bundle: nil)
let controller_UIKit = storyboard_UIKit.instantiateViewController(withIdentifier: "ViewControllerUIKit")
if #available(macCatalyst 14.0, iOS 14.0, *){
// SwiftUI
self.present(controller_swiftUI, animated: true)
} else {
// UIKit
self.present(controller_UIKit, animated: true)
}

Is there an overview of the text and string drawing system changes in iOS 7?

In iOS 7 some of the most important string drawing and metrics calculation methods were depracated with no obvious alternative given.
The page on NSString UIKit Additions Reference is red like blood. Almost everything deprecated. Xcode throws 300 warnings at me.
I try to find out what was running through Apples mind and what they changed in UIKit text system but where would I start? Did they mention somewhere why all of this is deprecated and how the text system works different now? And how to adapt? How to calculate text bounding box when label can scale the font to fit size? Is TextKit the solution?
I spent 3 hours on Google but I found no useful information on how to solve this problem.
We should document all alternatives here so all developers who run into this depressive deprecation mess find peace of mind quickly.
If you look at the deprecations, most of them deprecate the use of UIFont to use a dictionary of attributes instead.
drawInRect:withFont: (Deprecated in iOS 7.0. Use drawInRect:withAttributes: instead.)
drawInRect:withFont:lineBreakMode: (Deprecated in iOS 7.0. Use drawInRect:withAttributes: instead.)
sizeWithFont:(Deprecated in iOS 7.0. Use sizeWithAttributes: instead.)
etc…
So if you're looking for a place to start, learn how to use dictionaries of attributes to set up fonts. It looks like a lot of deprecations, but you don't actually need to learn that much new stuff.
If you want to update your code to use the new TextKit system, check out the WWDC videos and the TextKit Programming Guide.
If you want to know Apple's reason for deprecating so much, I'd guess that it has to do with how UILabel and UITextView used to be built on web views, now they're built on TextKit.

unarchiving NSAttributedString in iOS

I tried archiving an NSAttributedString in Mac OSX 10.7 and then tried to unarchive it in iOS 4.. I get an error:
cannot decode object of class (NSParagraphStyle)
I see that there's no NSParagraphStyle in iOS. So my question is, is there a workaround or is it not possible to this?
Perhaps you could use the NSKeyedUnarchiver method setClass:forClassName and provide a class of your own to use for NSParagraphStyle. That class would have to implement initWithCoder: and you could either ignore it or try to replicate NSParagraphStyle with what's available on iOS (CTParagraphStyle which is quite difficult to work with).

iphone Simulator crash?

I'm develop app for iPhone & iPod and during developing app i used simulator 3.2(iPad) it runs perfectly but when I want to my app on simulator 3.1.3 it generate one error I remove this error by comment this line //self.clearsSelectionOnViewWillAppear = NO;
and build project successfully but run app on simulator 3.1.3 when i clicking on button it goes on another screen on 3.2 simulator perfectly & crash on 3.1.3
what i do for come out from it.
The docs for UITableViewController clearly state that clearsSelectionOnViewWillAppear is available on iOS 3.2 and above. It crashes in 3.1.3 because this property does not exist in 3.1.3 (you can easily surmise this from reading the documentation for the property that you have already discovered is causing the issue, or from looking at the error message which will indicate that the object does not respond to a selector for setClearsSelectionOnViewWillAppear.
Before setting this, you can check for this property and then set it, otherwise your older code can just be supported as is, or you could do something more advanced and add the property in pre-3.2 environments.
To check for the code, you do something like this:
if( [UITableViewController instancesRespondToSelector:#selector(setClearsSelectionOnViewWillAppear:)] ) {
// This is 3.2+ so we can use this property
[self setClearsSelectionOnViewWillAppear:NO];
} else {
// This is something earlier than 3.2, so we ignore it
NSLog(#"will clear selection: pre-3.2");
}
Can you explain your question more clearly?
My dear friend,
You should read the Apple documentation more attentively,
It is clearly stated that
clearsSelectionOnViewWillAppear
is a method available from iPhone OS 3.2 and later,you are trying to use it in 3.1.3.
So the result is obvious.
clearsSelectionOnViewWillAppear
A Boolean value indicating if the controller clears the selection when the table appears.
#property(nonatomic) BOOL clearsSelectionOnViewWillAppear
Discussion
The default value of this property is YES. When YES, the table view controller clears the table’s current selection when it receives a viewWillAppear: message. Setting this property to NO preserves the selection.
Availability
Available in iPhone OS 3.2 and later.
Declared In
UITableViewController.h
Thanks

How to use iPhone OS 3.2 functionality in an iPhone OS 3.0 app?

Problem: My app must run on iPhone OS 3.0.
However, there are some features of iPhone OS 3.2 which I really want to use. Just as a little add-on for free. But I don't want to cut off my user base by doing this.
Imagine you're an iPhone OS 3.0 thing, and someone gives you a book to read. It has iPhone OS 3.2 instructions. You never learned those. So what do you do? Crash? They would have to be hidden, so you're not bothered.
Someone wrote recently on SO:
keep in mind that you have to check
the version at places in the source
code where you like to use the new
features and provide alternatives for
older os versions
So how could I do that? Wouldn't Xcode throw warnings when it finds stuff that isn't linkable from anything anywhere? Would I just check for the OS version and dynamically link - somehow - to whatever stuff I think is cool?
The two must common ways to detect features are respondsToSelector and NSClassFromString. With these you can tell if an old class has a new method, or if a new class exists.
For example, 3.2 added gesture recognizers. You could use either one of these methods to decide if you want to add gesture recognizers to a view:
if ( [myView respondsToSelector:#selector(addGestureRecognizer:)] ) {
// assume gesture recognizers exist, create and add some
}
or
if ( NSClassFromString( #"UIGestureRecognizer" ) ) {
// assume gesture recognizers exist, create and use some
}
In both cases, you would build for 3.2 but only use 3.2 features if they are detected at runtime. If you build against 3.0 and all the warnings show up in places where you are checking things correctly, then you are good to go.
In the case of 3.2 a new processor was also added, so either build a universal binary or build for the older architecture.
Also, in some cases Apple provides support for detecting version. A good example of that is UI_USER_INTERFACE_IDIOM in UIDevice.h where it calls respondsToSelector for you.
There is a section in the iPad Programming Guide that talks about this titled "Adding Runtime Checks for Newer Symbols". Basically, you can use NSClassFromString and instancesRespondToSelector: to determine if the functionality is there, and then the app can act accordingly.