I am adding all my 3D Touch actions in my app delegate but how can I update the subtitle of one of the actions throughout my app?
Take a look at this reference from Apple. The first code sample gives you what you need to modify an existing quick action with a new localizedTitle.
Here's the Objective-C code from the Apple example. In summary, you create a UIMutableApplicationShortcutItem with a mutable copy of the shortcut item you want to modify. Change the title and then replace the previous shortcut with the new one.
NSArray <UIApplicationShortcutItem *> *existingShortcutItems = [[UIApplication sharedApplication] shortcutItems];
UIApplicationShortcutItem *anExistingShortcutItem = [existingShortcutItems objectAtIndex: anIndex];
NSMutableArray <UIApplicationShortcutItem *> *updatedShortcutItems = [existingShortcutItems mutableCopy];
UIMutableApplicationShortcutItem *aMutableShortcutItem = [anExistingShortcutItem mutableCopy];
[aMutableShortcutItem setLocalizedTitle: #“New Title”];
[updatedShortcutItems replaceObjectAtIndex: anIndex withObject: aMutableShortcutItem];
[[UIApplication sharedApplication] setShortcutItems: updatedShortcutItems];
Related
In one of my app, I want to show the local notification and once it's shown in notification center, I want to updated it's content.
Is it possible in Swift ?
Thanks,
HP.
Not exactly. But you can remove it and add an new one with the new text.
Here's the solution for other visitors:
https://developer.sinnerschrader-mobile.com/ios-how-to-remove-a-notification-programmatically-from-ios-notification-center/582/
Using NSKeyedArchiver, I archived my old local notification to one path and when I wanted to remove it, I deleted it from that location.
It's working fine.
Edited :
1)Cache UILocalNotificaiton using NSKeyedArchiver
NSString *archivePath = [self cachePathWithKey:key];
[NSKeyedArchiver archiveRootObject:notification toFile:archivePath];
2) Show Notification
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
3) Remove Notification Whenever you want to remove it.
NSString *archivePath = [self cachePathWithKey:key];
UILocalNotification *cachedNotification = [self notificationForKey:key];
if (cachedNotification == nil) {
return NO;
}
[[UIApplication sharedApplication] cancelLocalNotification:cachedNotification];
[[NSFileManager defaultManager] removeItemAtPath:archivePath error:nil];
You can use this library also as I've used that one only.
https://github.com/sinnerschrader-mobile/s2m-toolbox-ios
Copy LocalNotificationHelper Folder in your project and User removeNotificationForKey and showNotification methods.
Thanks,
HP.
I am trying to implement a feature in iOS project that when you select a piece of text and highlight it you can then choose from the menu options to use another app like the default dictionary. Is it possible to do this? If so where can I find such documentation or tutorials?
You are describing the iOS menu. Look at the documentation on classes such as UIMenu, UIMenuItem, and UIMenuController.
I've found a solution to my problem.
Thanks to the author of this article:
http://blog.studiovillegas.com/2014/02/06/ios-uipasteboard-uimenucontroller-and-uimenuitem/
To add a custom menu item on to the default menu controller.
ViewController.h
- (void)longPressGestureRecognizer:(UIGestureRecognizer *)recognizer
{
UIMenuItem *mi = [self.label menuItemOpenPleco];
UIMenuController *menuController = [UIMenuController sharedMenuController];
menuController.menuItems = #[mi];
}
PasteboardLabel {h,m}
#interface PasteboardLabel : UILabel
- (UIMenuItem *)menuItemOpenPleco;
#end
#implementation PasteboardLabel
- (UIMenuItem *)menuItemOpenPleco
{
return [[UIMenuItem alloc] initWithTitle:#"Open Pleco" action:#selector(openPleco:)];
}
- (void)openPleco:(id)sender
{
NSString *selectedText = [self textInRange:[self selectedTextRange]];
UIPasteboard *pb = [UIPasteboard generalPasteboard];
pb.string = selectedText;
NSString *urlString = [NSString stringWithFormat:#"plecoapi://x-callback-url/q?s=%#", pb.string];
NSURL *url = [[NSURL alloc] initWithString:urlString];
[[UIApplication sharedApplication] openURL:url];
}
#end
I've found that there's a dearth of examples of adding custom menu items, or explanations of how they work. So I wanted to resolve that by sharing a few important tidbits then showing an example.
The UIMenuController "talks" with UIViews, not with UIViewControllers. This means that your UIMenuController related code needs to go into subclasses of UIView rather than a UIViewController.
Notice the word The at the start of my prior example. There's only one UIMenuController, a singleton which is shared from when your application first starts until it ends. This means that you should only add your item once, and that you shouldn't be writing over the existing array of items.
The appearance of the button in the UIMenu is based on whether or not the UIView that was tapped responds to the selector. This means you need to implement the method if you want the button to appear, and that you don't need to worry about it appearing when unrelated views are tapped unless you pick a selector name for which other UIViews also have methods.
So, having said all that, I made a subclass of a UITextView (which means its a subclass of UIView per my first bullet) and then I gave it this initialize method, along with an implementation for my selector.
+ (void)initialize {
static dispatch_once_t addInsert;
dispatch_once(&addInsert, ^{
UIMenuController *mController = [UIMenuController sharedMenuController];
UIMenuItem *insert = [[UIMenuItem alloc] initWithTitle:#"Insert..."
action:#selector(insert:)];
mController.menuItems = [mController.menuItems arrayByAddingObject:insert];
});
}
- (void)insert:(id)sender {
NSLog(#"Insert... pressed!");
}
The important points above here:
It's in the class initialize method, which is called by the runtime before the first time any other method in your class is invoked. In practice means the code is handled just before the first time an instance of your custom view will be appearing on screen.
I added a dispatch_once guard around it. If my class is subclassed, it's possible that those subclasses will call this initialize method. Maybe those subclasses show up before this one does, so I don't want to prevent the initialize method from running then. I just want to prevent it from running multiple times. Thus why I wrapped the code in a dispatch_once.
I didn't just set the menuItems to a new array of items - I assigned it to a new array of items that extended the existing array of items with my new item.
Hope you find all of that helpful. It's not very complicated, and you can certainly go about implementing my second point in other ways - I tried to pick a way that seemed safest to me, but there are certainly simpler ways of doing it.
I'm developing an app that will support multiple languages and I'm looking for the best way to set the different languages.
The app works with a UINavigationController. In the first ViewController you can select the language pressing a UIButton and then in the following view controllers the labels' texts would be changed to the corresponding language.
The way I'm doing it right now is by changing the value of a BOOL property when I create the instance of the new ViewController depending on the UIButton sender tag.
FirstViewController.m
-(void)goToSecondVC{
SecondViewController *secondVC = [[SecondViewController alloc]init];
if ([sender tag] == 1) {
secondVC.english = YES;
}else{
secondVC.english = NO;
}
[self.navigationController pushViewController:startScreenVC];
}
SecondViewController.m
-(void)viewWillAppear:(BOOL)animated{
if(self.english){
self.myLabel.text = #"This text will be in English";
}else{
self.myLabel.text = #"This text will be in Spanish";
}
I know this is probably not the best way to achieve this task. What would you recommend, notifications, delegation, singletons? I'm looking for a kind of global variable that could be written and read from every ViewController
You should be using localization for this.
You can get the language like this:
NSString *language = [[NSLocale currentLocale] objectForKey: NSLocaleLanguageCode];
Take a look at this this tutorial for localization:
http://www.raywenderlich.com/2876/localization-tutorial-for-ios
or this SO ansawer
The implementation is straightforward and correct.
Since you want to have this information known to every view controller, a better approach is to use KVO and a store for the language info value.
For example, save it to NSUserDefaults. Then from any view controller your could access it.
Then if some view controller wants to get notification when this value gets changed, it could observe the NSUserDefaults object for that value. (with Storyboard, you could use a Shared User Defaults Controller).
If you want to access the current language setting from any place in your app its worth taking a look at the Singleton design pattern. Here's an excellent summary.
You can also use the [NSUserDefaults standardUserDefaults] which is a predefined Singleton object or simply create your own.
I recently found how to program a switch and how to change the background from 1 view.
My question is how to change the background of multiple views (UIImage) when changing the value of the switch.
For example: It's a preference page and when I switch the background of the preferences page changes so the switch works.
Now i want the background (UIImage) of my first view named "viewcontroller" to change to the same background as the background of my preferences page.
in my opinion, there may be a lot of different ways to achieve this. What i would do is save the image name string into [NSUserDefaults standardUserDefaults].
Such as when the switch value changes, you call
[[NSUserDefaults standardUserDefaults] setObject:#"BackgroundImageName" forKey:#"BackgroundImageOne.jpg"];
[[NSUserDefaults standardUserDefaults]synchronize];
and when you set up the background, you could do
NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
UIImage *bgImage;
if ([userDefault objectForKey:#"BackgroundImageName"])
bgImage = [UIImage imageNamed:[userDefault objectForKey:#"BackgroundImageName"]];
else
bgImage = [UIImage imageNamed:#"DEFAULT_NAME"];
//... Set the bgImage to your background image view ...//
Maybe you have to do some changes based on the actual usage. But hope this give you some hints.
One of possible solutions would be to create a public property of application delegate holding your background image.
#property (strong) UIImage *globalBackground;
In your - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions you should initialize it either to some default image or last saved image.
self.globalBackground = [UIImage imageNamed:#"defaultBackground"];
Let's say your appDelegate header file is MyAppDelegate.h. You should import it in all the classes that use this default background image mechanism. Or simply add it to your Prefix.pch file.
In your settings view controller you would then set:
//your background setting handler
MyAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
appDelegate.globalBackground = ... //however you get the selected image
//and here you set the background image of settings view controller
Then in each of the view controllets viewWillAppear: you set its background in similar manner:
MyAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
//then you use appDelegate.globalBackground the same way you are doing it now
If you have a lot of view controllers you might want to consider creating a subclass of UIViewController that implements this mechanism (possibly calling it UIViewControllerWithBackground) and make all your view controllers subclasses of this class.
Note A: one would (instead of appDelegate's property) typically use a singleton class holding all the settings. It might be considered as a bad (quick & dirty) practice. More...
Note B: for saving the name of last selected background you could use NSUserDefaults. This is out of the scope of this question and there is a lot of sample code available out there...
Is it possible to pass the image, which I saved in Xcode, to a next viewcontroller? Or give it a number and pass that number to a next viewcontroller? For example, when switchone is on, NSNumber = 1, pass it to the next view, and then if (NSNumber == 1) than display "backgroundone.jpg"???
In iPhone can we set the lock screen, wallpaper and ringtone programmatically?
If Yes, then please let me know how to set them?
This can all be done easily, but will be rejected by Apple.
The ringtone can be changed by altering com.apple.SpringBoard.plist, specifically the ringtone key.
The following code can be used to read the actual ringtone title of custom ringtones (synced by iTunes).
NSMutableDictionary *custDict = [[NSMutableDictionary alloc] initWithContentsOfFile:#"/private/var/mobile/Media/iTunes_Control/iTunes/Ringtones.plist"];
NSMutableDictionary *dictionary = [custDict objectForKey:#"Ringtones"];
NSArray *keys = [dictionary allKeys];
id key = [keys objectAtIndex:indexPath.row];
NSMutableDictionary *customRingtone = [dictionary objectForKey:key];
NSString *name = [customRingtone objectForKey:#"Name"];
cell.textLabel.text = name;
The Wallpapers can be overwritten at:
NSString *homePath1 = #"/private/var/mobile/Library/SpringBoard/HomeBackground.jpg";
NSString *homePath2 = #"/private/var/mobile/Library/SpringBoard/HomeBackgroundPortrait.jpg";
NSString *lockPath1 = #"/private/var/mobile/Library/SpringBoard/LockBackground.jpg";
NSString *lockPath2 = #"/private/var/mobile/Library/SpringBoard/LockBackgroundPortrait.jpg";
These examples were used in one of my Cydia apps. Theres not really much more to them, but these should get you going in the right direction.
The answer by WrightsCS stopped working at some point due to a change in iOS. Unfortunately, this is something you have to live with if you wish to use undocumented features.
If you still need to do this, for non-App Store apps only, this code works in iOS 9.3. It could stop working in any future iOS release, though. (see comment below: no longer working in iOS 10)
#import "SBSUIWallpaperPreviewViewController.h"
#import <dlfcn.h>
// open the private framework dynamically
void *handle = dlopen("/System/Library/PrivateFrameworks/SpringBoardUIServices.framework/SpringBoardUIServices", RTLD_NOW);
UIImage *wallpaper = [UIImage imageNamed: #"background.jpg"];
Class sbClass = NSClassFromString(#"SBSUIWallpaperPreviewViewController");
// we create a view controller, but don't display it.
// just use it to load image and set wallpaper
SBSUIWallpaperPreviewViewController *controller = (SBSUIWallpaperPreviewViewController*)[[sbClass alloc] initWithImage: wallpaper];
[controller setWallpaperForLocations: 3]; // 3 -> set both for lock screen and home screen
dlclose(handle);
You'll need to add the private API header to your project. You can usually find these online with a little searching, for example, here.
In the example above, [SBSUIWallpaperPreviewViewController setWallpaperForLocations:] is called with an argument of 3: 3 indicates the image should be used for both lock and home screens. 1 indicates Lock screen only. 2 indicates Home screen only.
For an explanation of why I open this framework up dynamically, see my related answer here.
I don't have an answer regarding ringtones. This really should be a separate question: completely different APIs at work.
use private api if you can
check PLStaticWallpaperImageViewController