keyboard of grandparent view controller shows up when the other view controller is presented

The specific reason why keyboard is presented when the grand child(presentedViewController’s presentedViewController) view controller is presented is not found. But when the text of textfield is empty, this doesn’t happen. I set breakpoint on the resignFirstResponder, and I found when the text is empty resignFirstResponder is called when the view controller will disappear and not when the text is not empty.

Therefore I called resignFirstResponder manually when viewWillDisapper

DiffableDataSource iOS 14.6 bug

When items are appended by paging, the cell being shown is called on CellProvider.

Because I call image fadeIn animation in CellProvider, it looks like blinking on the cells which were already loaded before paging.

But this bug does not occur on 15.0, 15.4.1 and occurs on 14.6 and 13.7

https://developer.apple.com/forums/thread/680373?answerId=677642022#677642022

It happens on estimated cells & under iOS 15

iOS message app bug in 14.4-14.5

activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType

When I return url with query parameters in this method, query parameters get deleted in message app. This bug doesn’t occur in reminders, notes and other 3rd party apps. And it doesn’t occur on iOS 11.4. It also doesn’t occur if you use MFMessageComposeViewController.

[text appendString:[NSString stringWithFormat:@"\n%@\n", NSLocalizedString(@"ios_share.message", nil)]];
    [text appendString:[NSString stringWithFormat:@"%@/%@/contents/%@?ref=share", [NetworkManager.shared shareURL], RegionHelper.shared.currentLanguageWithRegion, content.cod]];
    
    MFMessageComposeViewController *messageViewController = [[MFMessageComposeViewController alloc] initWithBody:text sentMessage:NSLocalizedString(@"send_message_success", nil) failedMessage:nil];
    [UIViewController.currentViewController presentViewController:messageViewController animated:YES completion:nil];

I tried encoding, urlComponent, and returning absoluteString. Returning string without placeholder item worked but had same bug sometimes. To fix this issue, we changed the url format from query to path.

-> It’s now(21.5.26) fixed on 14.5.1

RemoveObserver before deinit

@implementation UIScrollView (WatchaInfiniteScrolling)

@dynamic infiniteScrollingView;

- (void)addInfiniteScrollingWithActionHandler:(void (^)(void))actionHandler {
    [self addObserver:self.infiniteScrollingView forKeyPath:@"contentInset" options:NSKeyValueObservingOptionNew context:nil];
}

@end

#pragma mark - InfiniteScrollingView
@implementation InfiniteScrollingView

- (void)willMoveToSuperview:(UIView *)newSuperview {
    if (self.superview && newSuperview == nil) {
        [scrollView removeObserver:self forKeyPath:@"contentInset"];
    }
}

@end

https://developer.apple.com/documentation/objectivec/nsobject/1408054-removeobserver?language=objc

I have to removeObserver before deinit. Calling removeObserver before adding makes error.

Calling removeObserver is not needed from iOS 9 -> It’s only subject to NotificationCenter.

https://developer.apple.com/documentation/foundation/notificationcenter/1413994-removeobserver

But in release note of macOS 10.13 and iOS 11 https://developer.apple.com/library/archive/releasenotes/Foundation/RN-Foundation/index.html

Relaxed Key-Value Observing Unregistration Requirements

Prior to 10.13, KVO would throw an exception if any observers were still registered after an autonotifying object’s -dealloc finished running. Additionally, if all observers were removed, but some were removed from another thread during dealloc, the exception would incorrectly still be thrown. This requirement has been relaxed in 10.13, subject to two conditions:

• The object must be using KVO autonotifying, rather than manually calling -will and -didChangeValueForKey: (i.e. it should not return NO from +automaticallyNotifiesObserversForKey:)
• The object must not override the (private) accessors for internal KVO state

If all of these are true, any remaining observers after -dealloc returns will be cleaned up by KVO; this is also somewhat more efficient than repeatedly calling -removeObserver methods.

It says you don’t need to removeObserver before deinit. But this works only from 11.2 and crash occurs in 11.1.

In iOS 14.3, alert controller title get truncated.

If you set “앗, 이 기기의 App Store 계정은 다른 테스트 ID(test@test.com)에서 이용권 구독 중인 것으로 확인되어요. 나나나” as message of the UIAlertController, in iOS 14.3, title gets truncated as “앗, 이 기기의 App Store 계정은 다른 테스트 ID(test@test.com)에서 이용권 구독 중인 것으로 확인되어…”. In iOS 13.7 and 11.3, the title doesn’t get truncated at all.

boldSystemFont returns “semibold”

(lldb) po UIFont.boldSystemFont(ofSize: 17)
font-family: “.SFUI-Semibold”; font-weight: bold; font-style: normal; font-size: 17.00pt

(lldb) po UIFont.systemFont(ofSize: 17, weight: .semibold)
font-family: “.SFUI-Semibold”; font-weight: bold; font-style: normal; font-size: 17.00pt

(lldb) po UIFont.systemFont(ofSize: 17, weight: .bold)
font-family: “.SFUI-Bold”; font-weight: bold; font-style: normal; font-size: 17.00pt

(lldb) po UIFont.systemFont(ofSize: 17)
font-family: “.SFUI-Regular”; font-weight: normal; font-style: normal; font-size: 17.00pt

sharedCookieStorage(forGroupContainerIdentifier doesn’t sync among targets sometimes

  1. cookies in app target -> no cookies in extension target
  2. no cookies in app target -> cookies exist in extension target

This two bugs occur sometimes. And sessionOnly cookie is not shared.

After struggling for a while, I changed to UserDefaults. UserDefaults work perfectly.

extension HTTPCookieStorage {
     func storeCookiesToUserDefaultsSharedGroup() {
         guard let userDefaults = UserDefaults.sharedGroup,
               let cookies = cookies else {
             return
         }
 

         var cookiesDictionary = [String : AnyObject]()
 

         for cookie in cookies {
             cookiesDictionary[cookie.name] = cookie.properties as AnyObject?
         }
 

         userDefaults.removeObject(forKey: Constants.UserDefaultKey.sharedGroupCookies)
         userDefaults.set(cookiesDictionary, forKey: Constants.UserDefaultKey.sharedGroupCookies)
     }
     
     func restoreCookiesFromUserDefaultsSharedGroup() {
         guard let userDefaults = UserDefaults.sharedGroup else {
             return
         }
         
         if let cookies = cookies {
             for cookie in cookies {
                 deleteCookie(cookie)
             }
         }
         
         if let cookies = userDefaults.dictionary(forKey: Constants.UserDefaultKey.sharedGroupCookies) {
             for (_, cookieProperties) in cookies {
                 if let cookie = HTTPCookie(properties: cookieProperties as! [HTTPCookiePropertyKey : Any] ) {
                     setCookie(cookie)
                 }
             }
         }
     }

Animating navigation bar from landscape to portrait view controller(dismissal)

When dismiss landscape view controller to portrait view controller, if the portrait view controller<A> is loaded when landscape view controller is on screen, navigation bar of <A> has landscape frame.

How to solve

 if let navigationController = navigationController {
            navigationBarToTransform = navigationController.navigationBar.transform
            navigationBarToTransform = navigationBarToTransform!.concatenating(CGAffineTransform(translationX: 0, y:  -0.001))
            navigationBarFromTransform = navigationBarToTransform!.concatenating(CGAffineTransform(translationX: 0, y: -navigationController.navigationBar.frame.height - navigationController.navigationBar.frame.origin.y))
            navigationController.navigationBar.transform = navigationBarFromTransform!
        }
        
        
        UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 0.95, initialSpringVelocity: 0.5, options: .curveEaseInOut,
                        animations: {
                            if let navigationBarToTransform = navigationBarToTransform {
                                navigationController?.navigationBar.transform = navigationBarToTransform
                            }
        },
                        completion: { finished in
                            
                            }
                            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
                            
        })

Even though I don’t know the mechanism, if I apply transition bigger than 0, the frame gets changed to portrait.

Animating (1)top View controller’s view rotation and (2)navigation bar going up -> view controller’s frame becomes small

if let navigationController = navigationController {
            navigationBarFromTransform = navigationController.navigationBar.transform
            navigationBarToTransform = navigationBarFromTransform!.concatenating(CGAffineTransform(translationX: 0, y: -navigationController.navigationBar.frame.height - navigationController.navigationBar.frame.origin.y))
        }

UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 0.95, initialSpringVelocity: 0.5, options: .curveEaseInOut,
                        animations: {
                            presentingViewController.view.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi/2)).scaledBy(x: scale, y: scale)
                            if let navigationBarToTransform = navigationBarToTransform {
                                navigationController?.navigationBar.transform = navigationBarToTransform
                            }
                            
        }

It’s same even if navigation bar animation uses frame not transform.