Showing posts with label ios9. Show all posts
Showing posts with label ios9. Show all posts

Wednesday, July 4, 2018

How do I get a monospace font that respects acessibility settings

Leave a Comment
let bodyFontDescriptor = UIFontDescriptor     .preferredFontDescriptor(withTextStyle: UIFontTextStyle.body) let bodyMonospacedFontDescriptor = bodyFontDescriptor.addingAttributes(     [         UIFontDescriptorFeatureSettingsAttribute: [             [                 UIFontFeatureTypeIdentifierKey: kTextSpacingType,                 UIFontFeatureSelectorIdentifierKey: kMonospacedTextSelector             ]         ]     ]) let bodyMonospacedFont = UIFont(descriptor: bodyMonospacedFontDescriptor, size: 0.0) textview.font = bodyMonospacedFont 

This produces text with characters of variable width. I need to get a monospace font without hardcoding courier new and fixed size. Deployment target is ios 9.0

1 Answers

Answers 1

Here is an extension to UIFontDescriptor that returns a preferred monospaced font descriptor for a given text style. There is no simple way to get a fully monospaced font using UIFont or UIFontDescriptor. This solution attempts to find a good monospaced font and falls back to Courier if needed.

extension UIFontDescriptor {     static let monoDescriptor: UIFontDescriptor = {         // Attempt to find a good monospaced, non-bold, non-italic font         for family in UIFont.familyNames {             for name in UIFont.fontNames(forFamilyName: family) {                 let f = UIFont(name: name, size: 12)!                 let fd = f.fontDescriptor                 let st = fd.symbolicTraits                 if st.contains(.traitMonoSpace) && !st.contains(.traitBold) && !st.contains(.traitItalic) && !st.contains(.traitExpanded) && !st.contains(.traitCondensed) {                     return fd                 }             }         }          return UIFontDescriptor(name: "Courier", size: 0) // fallback     }()      class func preferredMonoFontDescriptor(withTextStyle style: UIFontTextStyle) -> UIFontDescriptor {         // Use the following line if you need a fully monospaced font         let monoDescriptor = UIFontDescriptor.monoDescriptor          // Use the following two lines if you only need monospaced digits in the font         //let monoDigitFont = UIFont.monospacedDigitSystemFont(ofSize: 0, weight: .regular)         //let monoDescriptor = monoDigitFont.fontDescriptor          // Get the non-monospaced preferred font         let defaultFontDescriptor = preferredFontDescriptor(withTextStyle: style)         // Remove any attributes that specify a font family or name and remove the usage         // This will leave other attributes such as size and weight, etc.         var fontAttrs = defaultFontDescriptor.fontAttributes         fontAttrs.removeValue(forKey: .family)         fontAttrs.removeValue(forKey: .name)         fontAttrs.removeValue(forKey: .init(rawValue: "NSCTFontUIUsageAttribute"))         let monospacedFontDescriptor = monoDescriptor.addingAttributes(fontAttrs)          return monospacedFontDescriptor.withSymbolicTraits(defaultFontDescriptor.symbolicTraits) ?? monospacedFontDescriptor     } } 

Note the comments about whether you need a font that is fully monospaced or a font that just has monospaced digits. Comment/Uncomment those lines to suit your specific needs.

Sample usage:

let bodyMonospacedFont = UIFont(descriptor: .preferredMonoFontDescriptor(withTextStyle: .body), size: 0) textview.font = bodyMonospacedFont 

The following is some test code to confirm that the results of preferredMonoFontDescriptor(withTextStyle:) works properly for all styles:

let textStyles: [UIFontTextStyle] = [ .body, .callout, .caption1, .caption2, .footnote, .headline, .subheadline, .largeTitle, .title1, .title2, .title3 ] for style in textStyles {     let nfont = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: style), size: 0)     let mfont = UIFont(descriptor: .preferredMonoFontDescriptor(withTextStyle: style), size: 0)     print(style)     print(nfont)     print(mfont) } 

If you compare each pair of results, they have the same size, weight, and style, just a different font.

Read More

Sunday, July 16, 2017

UIActivityViewController unable to set subject when sharing to Gmail app

Leave a Comment

I see via sharing content from other apps that it is possible to set a different subject and body when using share sheet to share into the Gmail Mail app. I have implemented it and it works fine on the native mail app but not Gmail.

Going into Yelp and sharing a business then choosing gmail from the share sheet, I see that the subject and body are different. The subject contains the address of the business while the body contains the address + a link to the business on Yelp.

I have tried to replicate this logic with success on the native Mail app but not in the Gmail app.

I have tried the following:

Implementing UIActivityItemSource methods

UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[self] applicationActivities:nil];  - (id)activityViewControllerPlaceholderItem:(UIActivityViewController *)activityViewController {     return @""; }  - (id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType {        return @"body"; }  - (NSString *)activityViewController:(UIActivityViewController *)activityViewController subjectForActivityType:(NSString *)activityType {     return @"subject"; } 

Result

Apple Mail Subject set to "subject", Body set to "body"

Gmail Subject set to "body", Body set to "body"

- (NSString *)activityViewController:(UIActivityViewController *)activityViewController subjectForActivityType:(NSString *)activityType  

Is never called when sharing into the Gmail app.

I then try the more hack way of doing it

UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[@"body"] applicationActivities:nil]; [activityViewController setValue:@"subject" forKey:@"subject"]; 

Result

Apple Mail Subject set to "subject", Body set to "body"

Gmail Subject set to "body", Body set to "body"

Any way to make Gmail Behave like Apple Mail?

Again, I have seen that other applications like Yelp and Safari have gotten the proper behavior out of the Gmail app through share sheet. Any advice would be appreciated, thanks.

1 Answers

Answers 1

[_activityViewController setValue:subject forKey:@"subject"];-Not supported way.

Correct way to set body and subject (iOS 7.0 and later) - implement UIActivityItemSource protocol on item to share.

//  EmailDataProvider.h  @interface EmailItemProvider : NSObject <UIActivityItemSource>  @property (nonatomic, strong) NSString *subject; @property (nonatomic, strong) NSString *body;  @end   //  EmailDataProvider.m      @implementation EmailDataProvider  - (id)activityViewControllerPlaceholderItem:(UIActivityViewController *)activityViewController {     return _body; }  - (id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType {     return _body; }  - (NSString *)activityViewController:(UIActivityViewController *)activityViewController subjectForActivityType:(NSString *)activityType {     return _subject; }  @end 

And than present it:

EmailDataProvider *emailItem = [[EmailDataProvider alloc]init];  emailItem.subject = @"This is Subject text.";  emailItem.body = @"This is Body,set by programatically";  UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[emailItem]                                   applicationActivities:nil];  [self presentViewController:activityViewController animated:YES completion:nil]; 
Read More

Wednesday, February 15, 2017

iOS push notification settings after reinstall

Leave a Comment

For iOS8 there is option when iOS cache push notification permission for 24h and after reinstall I would not receive push notification alert.

And there is workaround:

Resetting the Push Notifications Permissions Alert on iOS

The first time a push-enabled app registers for push notifications, iOS asks the user if they wish to receive notifications for that app. Once the user has responded to this alert it is not presented again unless the device is restored or the app has been uninstalled for at least a day.

If you want to simulate a first-time run of your app, you can leave the app uninstalled for a day. You can achieve the latter without actually waiting a day by following these steps:

Delete your app from the device. Turn the device off completely and turn it back on. Go to Settings > General > Date & Time and set the date ahead a day or more. Turn the device off completely again and turn it back on. Source: https://developer.apple.com/library/ios/technotes/tn2265/_index.html

Q: But for iOS9+ there is no cached push permission, and after reinstall I received alert every time. Is there any option to cache my choice for 24h and use it after reinstall ?

3 Answers

Answers 1

No.

Push Notifications permissions alert on iOS normally comes whenever we are registering our app for remote notification.

So once the behavior of permissions alert is changed by respective iOS version, we cant handle it by our own.

I hope this might help you.

Answers 2

Let's get a basic Understanding about Push Notifications for iOS 8.0 and iOS 9.0 Or Later.

Solution : 1

Resetting the Push Notifications Permissions Alert on iOS

The first time a push-enabled app registers for push notifications, iOS asks the user if they wish to receive notifications for that app. Once the user has responded to this alert it is not presented again unless the device is restored or the app has been uninstalled for at least a day.

If you want to simulate a first-time run of your app, you can leave the app uninstalled for a day. You can achieve the later without actually waiting a day by following these steps:

 1. Delete your app from the device.   2. Turn the device off completely and turn it back on.   3. Go to Settings > General > Date & Time and set the date ahead a day or more.   4. Turn the device off completely again and turn it back on. 

Solution : 2

You can also change your bundle ID over and over while debugging, each time notifications will get queried fresh. Once you are satisfied with code return to original bundle ID.

Source:

How to get back "Allow Push Notifications" dialog after it was dismissed once?

Answers 3

try setting up a new iCloud account and see if that was it because I had the same problem and so i tried it and the new one would push while the old one would only retrieve if the mail app was open. If that does not help I have contacted the apple software developers and they have not responded you may have to wait until the 9.1 update release.

Read More

Monday, June 13, 2016

Batch delete request crashes app

Leave a Comment

I have an InMemory Store Coordinator declared like so:

lazy var ramStoreCoordinator: NSPersistentStoreCoordinator = {     // The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.     // Create the coordinator and store     let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)     var failureReason = "There was an error creating or loading the application's saved data."     do {         try coordinator.addPersistentStoreWithType(NSInMemoryStoreType, configuration: nil, URL: nil, options: nil)     } catch {         // Report any error we got.         var dict = [String: AnyObject]()         dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"         dict[NSLocalizedFailureReasonErrorKey] = failureReason          dict[NSUnderlyingErrorKey] = error as NSError         let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)         // Replace this with code to handle the error appropriately.         // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.         NSLog("Unresolved error \(wrappedError), \(wrappedError.userInfo)")         abort()     }      return coordinator }() 

as well as an associated ManagedObjectContext:

lazy var ramManagedObjectContext: NSManagedObjectContext = {     // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.     let coordinator = self.ramStoreCoordinator     var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)     managedObjectContext.persistentStoreCoordinator = coordinator     managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy     return managedObjectContext }() 

I'm trying to execute a fetch request like so:

    let fetchRequest = NSFetchRequest(entityName: "Post")     let batchDelete = NSBatchDeleteRequest(fetchRequest: fetchRequest)     do {         // Execute Batch Request         try ramManagedObjectContext.executeRequest(batchDelete)     } catch {         let updateError = error as NSError         print("\(updateError), \(updateError.userInfo)")     } 

the line:

try ramManagedObjectContext.executeRequest(batchDelete) 

crashes the app with the following output:

2016-04-30 23:47:40.271 Secret[2368:1047869] * Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Unknown command type (entity: EntityName; predicate: ((null)); sortDescriptors: ((null)); type: NSManagedObjectIDResultType; ) >' * First throw call stack: (0x18145ae38 0x180abff80 0x1833710b0 0x18338991c 0x183391d64 0x101121a3c 0x10112d5f0 0x1833845bc 0x1832c1d5c 0x183354e04 0x10011abc4 0x10011947c 0x100092bf0 0x10009269c 0x1000926ec 0x186a1aac0 0x186a1b258 0x186901854 0x186904a4c 0x1866d4fd8 0x1865e0014 0x1865dfb10 0x1865df998 0x183f4da20 0x101121a3c 0x1011274e4 0x181410dd8 0x18140ec40 0x181338d10 0x182c20088 0x18660df70 0x1000fcba8 0x180ed68b8) libc++abi.dylib: terminating with uncaught exception of type NSException

3 Answers

Answers 1

NSBatchDeleteRequest should be executed on your ramStoreCoordinator, not ramManagedObjectContext, since it works directly with NSPersistenceStore class instance:

try persistentStoreCoordinator.executeFetchRequest(batchDelete, withContext: ramManagedObjectContext) 

Check this link for more details: https://developer.apple.com/videos/play/wwdc2015/220/

Hope it helped)

Answers 2

I had the exact same problem. Solved it by changing the in memory store to NSSQLiteStoreType . Have not done any research why this happens to in memory store, but I hope that solves your problem.

Answers 3

This error can occur when you rename some files outside XCode. To solve it you can just remove the files from your project (Right Click - Delete and "Remove Reference") You re-import the files in your project and everything will be ok !

If it didn't fix, try this

try persistentStoreCoordinator.executeFetchRequest(     batchDelete, withContext:context ) 

as NSBatchDeleteRequest is executed on the persistent store coordinator, not the managed object context.

Read More

Sunday, April 17, 2016

xcode iOS 9 Keyboard Issue

Leave a Comment

My old project is having an issue with the iOS 9 Keyboard. After the library that I developed was installed through Cocoapods, I am getting this error on the simulator when trying to use the Keyboard.

-[UIWindow endDisablingInterfaceAutorotationAnimated:] called on <UIRemoteKeyboardWindow: 0x78f0ff60; frame = (0 0; 1024 768); opaque = NO; autoresize = W+H; layer = <UIWindowLayer: 0x78f10240>> without matching -beginDisablingInterfaceAutorotation. Ignoring. 

Keyboard behavior:

  • Letters with 'accents' (example: â) are popping up even without holding the character

  • The dismiss keyboard button does not dismiss the Keyboard. It will only display the options 'Split' and 'Dock'

Any ideas on why is this happening? Thanks very much

1 Answers

Answers 1

Try reinstalling Xcode, because maybe the application became corrupt somehow, and if that doesn't work, also try deleting its library files (~/library/application support/xcode and ~/library/containers/xcode) because they might also be corrupt. Hope this helps!

Read More

NSNetServiceBrowser cannot find services whereas NsdManager discovering it for android

Leave a Comment

I have written my bonjour discovery code for service of type _coap._udp..

static NSString* kTRServiceType = @"_coap._udp."; static NSString* kTRDomain      = @"";   -(void) startBrowsing{ [self.serviceBrowser searchForServicesOfType:kTRServiceType inDomain:kTRDomain];} 

Its discovering 2 services out of 3 whereas NsdManager discovering all 3.

My NSNetServiceBrowser object is not local as this could be a general mistake.

One service that NSNetServiceBrowser is not discovering is also not visible in Bonjour Browser App. But when i do Reload Services in Bonjour Browser App that service become discoverable .Its like reload services awakes my sleeping published service. Its really strange.

0 Answers

Read More

Thursday, March 24, 2016

Can't find Keychain value when running from XCode

Leave a Comment

I'm using SSKeychain to store a session token. When I compile and run the app from XCode, sometimes the token cannot be found (seems like it works sporadically). However, if I unplug my device and run the app without XCode, the token is back, 10/10 times. I'm not sure if this is a problem with SSKeychain or with Keychain in general. The code I'm using to store and read values is the following:

- (void)setSecureValue:(NSString *)value forKey:(NSString *)key {     [SSKeychain setPassword:value forService:kServiceName account:key]; }  - (NSString *)secureValueForKey:(NSString *)key {     if (key != nil)     {         return [SSKeychain passwordForService:kServiceName account:key];     }     return nil; } 

Many issues revolving Keychain access seem to be resolved by realizing that the keychain is not a data storage and that it can be emptied at times (due to memory warnings, for example). However, since I always run on the same device, and the token is still there after unplugging and running again, I don't see how this could be the issue here.

1 Answers

Answers 1

This is a bug of the keychain itself. If you are debugging the app on device, the app security needs to be breached to enable the debugging mode and that's why the keychain doesn't work somehow

Read More

Friday, March 11, 2016

iOS Data Storage issue - Rejected even after NSURLIsExcludedFromBackupKey

Leave a Comment

My app is rejected from app store multiple times for not following 'iOS Data Storage Guidelines'. I have marked all document directories with "do not back up" attribute as suggested by apple review team, as shown:

- (BOOL)addSkipBackupAttributeToItemAtPath:(NSString *) filePathString {     NSURL* URL= [NSURL URLWithString:filePathString];      NSError *error = nil;     BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES]                                   forKey: NSURLIsExcludedFromBackupKey error: &error];      return success; } 

I have called the above addSkipBackupAttributeToItemAtPath method for all NSDocumentDirectory as shown :

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);     [self addSkipBackupAttributeToItemAtPath:[paths objectAtIndex:0]]; 

and review team says it is still storing some data as backup to iCloud and it is being rejected by Apple review team, actually i don't want anything to back up. Is there anything i have missed to Skip Backup Attribute? or anything wrong in my code? please help. Thank you.

2 Answers

Answers 1

Write this code in addSkipBackupAttributeToPath method. I had the same issue and was resolved by writing this code instead.

- (void)addSkipBackupAttributeToPath:(NSString*)path {    u_int8_t b = 1;    setxattr([path fileSystemRepresentation], "com.apple.MobileBackup", &b, 1, 0, 0); } 

Answers 2

Try using the NSCachesDirectory instead of the NSDocumentDirectory, to store the subfolders/files.

Read More