I have use the custom splitview in the my application.
custom splitview .h file
#interface CustomUISplitViewController :UISplitViewController {
BOOL keepMasterInPortraitMode;
BOOL keepMasterInPortraitMode1;
}
and .m file is
-(void) viewWillAppear:(BOOL)animated {
keepMasterInPortraitMode1=keepMasterInPortraitMode;
if(keepMasterInPortraitMode1 == NO) {
if (self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft || self.interfaceOrientation == UIInterfaceOrientationLandscapeRight) {
UIViewController* master = [self.viewControllers objectAtIndex:0];
UIViewController* detail = [self.viewControllers objectAtIndex:1];
[self setupPortraitMode:master detail:detail];
}
}
if (self.interfaceOrientation == UIInterfaceOrientationPortrait || self.interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
UIViewController* master = [self.viewControllers objectAtIndex:0];
UIViewController* detail = [self.viewControllers objectAtIndex:1];
[self setupPortraitMode:master detail:detail];
}
}
}
- (void)setupPortraitMode:(UIViewController*)master detail:(UIViewController*)detail {
//adjust master view
CGRect f = master.view.frame;
f.size.width = 220;
f.size.height = 1024;
f.origin.x = 0;
f.origin.y =0;
[master.view setFrame:f];
//adjust detail view
f = detail.view.frame;
f.size.width = 548;
f.size.height = 1024;
f.origin.x = 221;
f.origin.y = 0;
[detail.view setFrame:f];
}
This works correctly under iOS4.0 but under 4.2 I see only one view when the app runs. What could change between OS versions?
I was having the same issue and I believe this to be an Apple bug (I filed it a month ago with no response from them.) For me, it was specifically the "detail" view that was blank when the app started at orientation UIInterfaceOrientationLandscapeRight (3). It would look like this: http://d.pr/cGcU. This would occur when I restricted one of the two view controllers (say, the RootViewController) to landscape-only:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return UIInterfaceOrientationIsLandscape(interfaceOrientation);
}
With this in place, the following would occur during the detail view's initialization:
2010-11-15 20:17:47.792 MultipleDetailViews[96250:207] firstDetailViewController willAnimateRotationToInterfaceOrientation: 3 (landscape)
2010-11-15 20:17:47.792 MultipleDetailViews[96250:207] self.view.hidden is: 0
2010-11-15 20:17:47.799 MultipleDetailViews[96250:207] rotating...
2010-11-15 20:17:47.848 MultipleDetailViews[96250:207] firstDetailViewController didRotateFromInterfaceOrientation
2010-11-15 20:17:47.849 MultipleDetailViews[96250:207] self.view.hidden is: 1
For some reason the detail view would mysteriously become hidden during rotation to orientation 3. Until Apple fixes this bug (it doesn't occur in 3.2), my workaround is currently to override the following method in the detail view controller, re-displaying the view after rotation has completed:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
self.view.hidden = NO;
}
EDIT: If your detail view isn't a direct subview of splitViewController.view (e.g. you are using a UINavigationController), you will need to set hidden on the topmost view on the detail side within the UISplitViewController:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
// Make sure you set splitViewController via an outlet or get it via your AppDelegate
for (UIView *splitViewChild in splitViewController.view.subviews)
splitViewChild.hidden = NO;
}
I have had the exact same problem with my applications. I had used the same Subclassing technique to have the Master and Detail visible in both Portrait and Landscape modes. Worked great until 4.2 which, unfortunately I didn't test for when the Beta releases were available.
I recommend trying the excellent MGSplitViewController (http://mattgemmell.com/2010/07/31/mgsplitviewcontroller-for-ipad). It is an open-source implementation of the UISplitViewController. It's only drawback is that it isn't quite as easy to use in Interface Builder, but it includes a sample project. Visually it is identical to UISplitViewController, but adds support for several extras such as dragging the split position at runtime.
Just implement it exactly as your UISplitViewController but add the following line somewhere:
[splitViewController setShowsMasterInPortrait:YES];
This is very similar to the Private API that Apple prohibits using with their version.
//[splitViewController setHidesMasterViewInPortrait:NO]; // Naughty, Naughty, Not allowed by the Apple police
Related
So I have a Universal link that leads to a view controller in my app. On that particular view controller I display a couple of images as well as a web view. The webView displays a url chosen by the user. How do I save this custom url so that it is displayed every time someone clicks the link? I think the code to this is under:
#synthesize deepLinkingCompletionDelegate;
-(void)configureControlWithData:(NSDictionary *)data {
NSString *string = data[#"favoriteArticle"];
Alex from Branch.io here:
To accomplish this, you need to do two things.
Step 1
Store the URL of the article you want to load as one of the Branch link custom parameters. Full instructions on how to do that here, but essentially:
BranchUniversalObject *branchUniversalObject = [[BranchUniversalObject alloc] initWithCanonicalIdentifier:#"item/12345"];
branchUniversalObject.title = #"My Content Title";
branchUniversalObject.contentDescription = #"My Content Description";
branchUniversalObject.imageUrl = #"https://example.com/mycontent-12345.png";
[branchUniversalObject addMetadataKey:#"favorite_article" value:#"https://example.com/path/to/article"]; // this is used to route inside the app
[branchUniversalObject addMetadataKey:#"property2" value:#"red"];
BranchLinkProperties *linkProperties = [[BranchLinkProperties alloc] init];
linkProperties.feature = #"sharing";
linkProperties.channel = #"facebook";
[linkProperties addControlParam:#"$desktop_url" withValue:#"https://example.com/path/to/article"]; // this is used for desktop visitors
[linkProperties addControlParam:#"$ios_url" withValue:#"https://example.com/path/to/article"]; // this is used for iOS mobile visitors without the app installed
Step 2
Then when the app opens after a link click, watch for that data key. Again, full instructions, but basically:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// initialize the session, setup a deep link handler
[[Branch getInstance] initSessionWithLaunchOptions:launchOptions
andRegisterDeepLinkHandler:^(NSDictionary *params, NSError *error) {
// start setting up the view controller hierarchy
UINavigationController *navC = (UINavigationController *)self.window.rootViewController;
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *nextVC;
// If the key 'favoriteArticle' is present in the deep link dictionary
// then load the picture screen with the appropriate picture
NSString * favoriteArticle = [params objectForKey:#"favorite_article"];
if (favoriteArticle) {
nextVC = [storyboard instantiateViewControllerWithIdentifier:#"ArticleVC"];
[nextVC setArticleUrl: favoriteArticle];
} else {
nextVC = [storyboard instantiateViewControllerWithIdentifier:#"MainVC"];
}
// navigate!
[navC setViewControllers:#[nextVC] animated:YES];
}];
return YES;
}
After this, in your ArticleVC, retrieve the favoriteArticle value and use it for your webview.
Step 2 (Alternate)
The configureControlWithData method you mentioned is used in the automatic deep link routing implementation. You may be able to adapt this to work with a webview, but I haven't personally tried that. It would look something like this:
#synthesize deepLinkingCompletionDelegate;
- (void)configureControlWithData:(NSDictionary *)data {
NSString *favoriteArticle = data[#"favorite_article"];
// load the webview with the URL stored inside favoriteArticle
}
I recently received this error when fetching data from Core Data:
warning: could not load any Objective-C class information. This will significantly reduce the quality of type information available.
(lldb)
Here is my code:
// MARK: - Initialize Fetch Request
var fetchedResultsController = NSFetchedResultsController<Profile>()
func setFetchRequest() -> NSFetchRequest<Profile> {
let request = Profile.fetchRequest()
let sortDescriptor = SortDescriptor(key: "title", ascending: false)
do {
try moc?.fetch(request)
} catch {
print("Error With Request: \(error)")
}
request.sortDescriptors = [sortDescriptor]
return setFetchRequest()
}
// MARK: - Retrieve Fetch Request
func getFetchRequest() -> NSFetchedResultsController<Profile> {
fetchedResultsController = NSFetchedResultsController(fetchRequest: setFetchRequest(), managedObjectContext: moc!, sectionNameKeyPath: nil, cacheName: nil)
return fetchedResultsController
}
I crashed with this error where I have "try moc?.fetch(request)":
Thread 1 EXC_BAD_ACCESS (code=2, address=0x16fc07feo)
Are these errors connected or is this a bug in Swift 3 / Xcode 8?
You shouldn't take results from the ManagedObjectContext. If you want to use a NSFetchedResultsController class in your app? You'll need to access their methods. And all of the required or optional methods are comes from the NSFetchedResultsControllerDelegate protocol.
Try this
class YourTableViewController: UITableViewController, NSFetchedResultsControllerDelegate {
var fetchedResultsController:NSFetchedResultsController<Profile>!
}
And then create a custom helper function like this one:
`func frc() {
let request:NSFetchRequest<Profile> = Profile.fetchRequest()
let sorter = SortDescriptor(key: "title", ascending: true)
request.sortDescriptors = [sorter]
self.fetchedResultsController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: self.managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
// make sure the delegate is set to self
self.fetchedResultsController.delegate = self
do {
try self.fetchedResultsController.performFetch()
} catch {}
}
`
From this point you'll need a trigger to perform operations. So let's the system itself should be doing this when you call the viewDidLoad method or you can create a button instead. For example click the button to begin operations.
override func viewDidLoad() {
super.viewDidLoad()
self.frc()
self.tableView.reloadData()
}
It should be works.
Good luck!
Automatic Subclass Generation
Xcode 8 and Swift 3 comes with a new generation of subclassing called as Automatic Subclass Generation! How to create it? Well! So let's create a new Xcode 8 project, choose a Single View Application and then another window will appears called Choose options for your new project:. Give the name for your new project, make sure language is a Swift and Use Core Data check box is checked and then hit Create.
Go to the YourProjectName.xcdatamodeld file and click it. And then add an entity! So let's say your entity name is a Profile and create their Attributes respectively. It's important to know, because this is an Automatic Subclass Generation. Choose your entity and go to the Data Model Inspector ! Choose a Class Definition for the Codegen You can find a Codegen from here.
After selected the Class Definition, you can see Name text field automatically filled by your entity name like so. Again go to the your entity and click it. Click Command + S for save changes firstly and then click Command + B for rebuild, that's it. Automatic Subclass Generation is successfully created.
Remember
If you want to change your model? For example: If you want to add a new Attribute to your model? It's very easy, select a xcdatamodeld file and click your entity. Click the plus sign under Attributes and add your new Attribute. After your changes is completed? Don't forget to save changes. Again click Command + S and then click Command + B
Create A Managed Object
In the Swift 3 you can create a ManagedObject by using subclass initializer. It's very easy to implementing than ever before
let managedObject = Profile(context: self.managedObjectContext!)
You can see it's very easy! How to save values to the managedObject ? So let's say you have a title attribute of your model. Also title is a String.
managedObject.setValue("Well crafted API? Right?", forKey: "title")
or
managedObject.title = "Well crafted API? Right?"
Save values:
do {
try self.managedObjectContext.save()
print(managedObject)
} catch {}
It's works well on the Swift 3.0 beta and Xcode 8.0 beta.
Update
So, this is what I got working for Xcode 8 beta and Swift 3 beta Core Data
var fetchedResultsControler = NSFetchedResultsController<Profile>()
func frc() {
let request: NSFetchRequest<Profile> = Profile.fetchRequest()
let sortDescriptor = SortDescriptor(key: "title", ascending: true)
request.sortDescriptors = [sortDescriptor]
self.fetchedResultsControler = NSFetchedResultsController(fetchRequest: request, managedObjectContext: self.moc!, sectionNameKeyPath: nil, cacheName: nil)
self.fetchedResultsControler.delegate = self
do {
try self.fetchedResultsControler.performFetch()
} catch {
print("Error Fetching Data: \(error)")
}
}
and in viewDidLoad I have self.frc() at the top of the viewDidLoad.
So, in my Profile+CoreDataProperties.swift I copied a method Apple uses in their Master-Detail example when you create a new project:
extension Profile {
#nonobjc class func fetchRequest() -> NSFetchRequest<Profile> {
return NSFetchRequest<Profile>(entityName: "Profile");
}
#NSManaged var title: String?
#NSManaged var titleImage: Data
}
so that my fetch request is "native to my function." Pretty sure that's not the correct way to say that but it's helping me understand what is going on. The fetch request in Apple's example is green instead of blue. And it took me forever to notice that. I clicked on "Event" in Apple's example, and was conveniently taken to the created subclass, which was demonstrated in the Xcode 8 video at WWDC.
The files for e.g. Event.swift and Event+CoreDataProperties.swift are not exposed like they are in Xcode 7.x.x and earlier. You have to click on the entity in the code and you'll be taken to them. Maybe that was my problem? Anyway, I'm fetching data and images like a champ. Thanks a lot for your help #Mannopson!
Converting a legacy app for iOS 7. Have most of the problems covered, but we have a feature that emails an error log using MFMailComposeViewController, and the status bar is coming up black on black in that view.
The status bar text color is set to white globally using plist settings, and that seems to handle everything else just fine. Only the email VC is acting up. (We present it using presentModalViewController.)
Has anyone figured out how to crack this nut?
Update: Tried subclassing MFMailComposeViewController and implementing preferredStatusBarStyle, but it's not invoked, even after setting "View controller-based status bar" to YES in the plist.
The following kluge appears to do the job:
// Present the email controller. The delegate will dismiss it.
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000
float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
if (systemVersion < 7.0f) {
[viewController presentViewController:emailController animated:YES completion:^{}];
}
else {
// Need a song and dance to get the header bar to show correctly. (And presentModalViewController is deprecated anyway.) Note that this code doesn't actually change the email controller's header, but it somehow lets the header below "show through" when it wouldn't otherwise. (I know -- like many of the iOS 7 fixes this makes no sense. But it works. (So far.))
#warning Sometimes produces console message "Presenting view controllers on detached view controllers is discouraged <XxxxViewController: 0xc658a70>"
[viewController presentViewController:emailController animated:YES completion:^{
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
if (([[[UIDevice currentDevice] systemVersion] floatValue] >= 7)
&& [[UIApplication sharedApplication] respondsToSelector:NSSelectorFromString(#"setStatusBarStyle:")]) {
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
}
#endif
}];
}
#else
[viewController presentModalViewController:emailController animated:YES];
#endif
If you see in ios 7 safari app have left and right dragging to see history of webpages. It also show content of previous page while dragging . I want similar functionality using UIWebiview.
I can get forward and backward page but how that dragging functionality with displaying previous content will be implemented?
Note: this is iOS 7 only. For iOS 6 you should use the PanGestureRecognizer and detect if it's left or right.
Your need two properties:
#property (nonatomic, strong) UIImageView * imgvcChild1;
#property (retain, strong) IBOutlet UIWebView *webView;
First of all, add the gesture recognizer to the webView:
[[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:#selector(EdgeLeftPanDetected:)];
panLeft.edges = UIRectEdgeLeft;
[self.webView addGestureRecognizer:panLeft];
Control the gesture:
- (void) EdgeLeftPanDetected:(UIScreenEdgePanGestureRecognizer*)gesture {
if (gesture.state == UIGestureRecognizerStateBegan) {
UIGraphicsBeginImageContext ( self.webView.frame.size );
[self.webView.layer renderInContext:UIGraphicsGetCurrentContext() ];
UIImage *grab = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
if ( _imgvcChild1 ) [ _imgvcChild1 removeFromSuperview ];
_imgvcChild1 = [[ UIImageView alloc ] initWithImage:grab ];
_imgvcChild1.frame = self.webView.frame;
_imgvcChild1.userInteractionEnabled = YES;
_imgvcChild2 = [self.arrayImagenes lastObject];
if ([self.webView canGoBack]) {
[self.webView goBack];
}
[ self.view addSubview:_imgvcChild1 ];
}
if (gesture.state == UIGestureRecognizerStateChanged) {
_imgvcChild1.frame = CGRectMake([ gesture locationInView:_imgvcChild1.superview ].x, _imgvcChild1.frame.origin.y, _imgvcChild1.frame.size.width, _imgvcChild1.frame.size.height);
}
}
if (gesture.state == UIGestureRecognizerStateEnded) {
[_imgvcChild1 removeFromSuperview];
}
}
This a prototype, it needs a lot of work, it's just for going back and the page where you go back doesn't have animation. If you want to have animation in the previous page you'll need to create a image before loading the new page and store it on an NSMutableArray and then show it with a different animation (this image starts like -1/4 of screen and goes like 1/4 of the speed of imgvcChild1)
You'll need another gesture recognizer for the right and another array of UIImageViews if you want to go forward too.
Few days back i too have similar kind of requirement. I did lot of research for this, but no luck. I read somewhere that this kind of gesture (History dragging) are managed by OS or the browser itself.
History dragging gesture are not available for UIWebView. As of now you cannot do this with UIWebView.
The one gesture will implement to achieve near to this functionality is UIPanGestureRecognizer but, you still not get the content of the previous page(history).
I'm rather new to iOS development and for my first real app I'm using a TapDetectingWindow to detect touches on a UIWebView (exactly as detailed on http://mithin.in/2009/08/26/detecting-taps-and-events-on-uiwebview-the-right-way).
I used it in one View Controller as suggested with a reference in the header file and the following in the implementation file;
- (void)viewDidLoad {
[super viewDidLoad];
mWindow = (TapDetectingWindow *)[[UIApplication sharedApplication].windows objectAtIndex:0];
mWindow.viewToObserve = igWeb;
mWindow.controllerThatObserves = self;
- (void)userDidTapWebView:(NSArray *)tapPoint {
}
It worked perfectly.
Now the problem is that I would like to use the TapDetectingWindow in a second View Controller.
I copied the same code from the first view controller (only changing the name of the viewToObserve).
Now, when I run the app. The Tap Detecting window works fine in the first ViewController, then works fine when you go to the second View Controller but when you go back to the first view controller its broken until the view gets loaded again.
Please help.
try something like
-(void)viewWillAppear:(BOOL)animated
{
mWindow.viewToObserve = igWeb;
mWindow.controllerThatObserves = self;
[super viewWillAppear:animated];
}