Sorry for the stupid question but i don't know how to present a view controller using objc_util.
Can someone help me?
Thanks in Advance,
Filippo
Forum Archive
Presenting ViewController
The first thing you'll need is a view controller you can present from. In most cases, the root view controller of the key window will do. You can get it like this:
root_vc = UIApplication.sharedApplication().keyWindow().rootViewController()
Note however that presenting from the root view controller will fail if it is already presenting some other view controller. This may be the case if the settings are shown or something like that. You could get around it like this:
while root_vc.presentedViewController():
root_vc = root_vc.presentedViewController()
Once you have a presenting view controller, you can call presentViewController_animated_completion_:
my_vc = ... # assuming you have a view controller you want to present
root_vc.presentViewController_animated_completion_(my_vc, True, None)
For now, just always pass None for the completion parameter. animated can be True or False, depending on whether you want a transition animation.
You can tweak the presentation by setting your view controller's modalPresentationStyle and modalTransitionStyle properties. E.g. to present the view controller in the "form sheet" style, use
my_vc.setModalPresentationStyle_(2)
I think your best option is to grab the view controller of a presented ui.View, and add your new controllers view as a subview, and there are a fw other methods to make sure the childcontroller is set up right. Here is a method to grab the currently presented view controller:
# coding: utf-8
from objc_util import *
def get_view_controller(uiview):
if isinstance(uiview,ui.View):
viewobj=ObjCInstance(uiview)
elif isa(uiview,'ObjCInstance') and uiview.isKindOfClass_(ObjCClass('UIView')):
viewobj=uiview
viewResponder=viewobj.nextResponder()
try:
while not viewResponder.isKindOfClass_(ObjCClass('UIViewController')):
viewResponder=viewResponder.nextResponder()
except AttributeError:
return None #if view is not being presented for example
return viewResponder
note this only works if the ui.View is being presented at the time.
complete example might look like
root_view_controller= get_view_controller(root)
someothercontroller.view().setFrame_(ObjCInstance(root).bounds())
ObjCInstance(root).addSubview_(someothercontroller.view())
root_view_controller.addChildViewVontroller(someothercontroller)
someothercontroller.didMoveToParentViewController_(root_view_controller)
you may also need to do some cleanup when the view is closed, but not sure...
Ok, i was trying to do this without any help but i'm stuck.
I basically have this code
from objc_util import *
from time import sleep
#import objutil
ObjCClass('NSBundle').bundleWithPath_('/System/Library/Frameworks/ReplayKit.framework').load()
recorder=ObjCClass('RPScreenRecorder')
preview=ObjCClass('RPPreviewViewController')
sharedrecorder=recorder.sharedRecorder()
sharedrecorder.startRecordingWithMicrophoneEnabled_handler_(False,None)#(false,none)
print 'Recording:' + str(sharedrecorder.isRecording())
print 'Microphone Enabled:' + str(sharedrecorder.isMicrophoneEnabled())
sleep(3)
#Some cool things...
#Stopping the recording and saving
print 'Stopping...'
sharedrecorder.stopRecordingWithHandler_(preview)
app = ObjCClass('UIApplication').sharedApplication()
rootvc=app.keyWindow().rootViewController()
rootvc.presentViewController_animated_completion_(preview, True, None)
That "implements" a iOS 9 API (ReplayKit) and records the screen for a certain time (3 secs in this case) and then it has to present the preview view controller. But the app crashes.
Can someone help me (again)?
Thanks in advance
Filippo
The problem is, you pass a view controller class to stopRecordingWithHandler_, but it expects a block... With the current beta, it's pretty difficult to make this work at all (blocks aren't really supported), but I can show you an example when the new build is up on TestFlight (probably later today). As it happens, I've been experimenting with exactly this API as well...
Thanks, waiting for it :-)
Okay, here's a minimal example that shows how you can use RPScreenRecorder β as I said, it'll only work with the latest build (#160023), so please install that first.
Note to others who might be reading this: You also need to have the iOS 9 beta installed for this to work.
from objc_util import *
import time
NSBundle = ObjCClass('NSBundle')
replaykit = NSBundle.bundleWithPath_('/System/Library/Frameworks/ReplayKit.framework')
replaykit.load()
RPScreenRecorder = ObjCClass('RPScreenRecorder')
def stop_callback(_cmd, _vc):
vc = ObjCInstance(_vc)
rootvc = UIApplication.sharedApplication().keyWindow().rootViewController()
vc.popoverPresentationController().setSourceView_(rootvc.view())
rootvc.presentViewController_animated_completion_(vc, True, None)
stop_handler = ObjCBlock(stop_callback, restype=None, argtypes=[c_void_p, c_void_p])
recorder = RPScreenRecorder.sharedRecorder()
@on_main_thread
def start_recording():
recorder.startRecordingWithMicrophoneEnabled_handler_(False, None)
@on_main_thread
def stop_recording():
recorder.stopRecordingWithHandler_(stop_handler)
start_recording()
time.sleep(5)
stop_recording()
Thanks.
What is @on_main_thread for?
What is @on_main_thread for?
I think it's not strictly necessary here, but most things that have to do with UI need to be called from the main thread.
It crashes :-( i copied exactly what you wrote and crashes π±
Hmm. What kind of device do you have? Could be that it doesn't work on 32 bit...
Ipad air 2, it is 64 bit. I noticed removing on main thread crashes the app after the recording and before the presentation, leaving it crashes when start_recording() is called
Okay, no idea what might be causing the crash then, sorry. :/
It doesn't crash here at all, but I've noticed that the resulting videos contain strange artifacts (looks like tearing), not sure if that's related somehow.
Ok, will try to solve it by me :-/
If you find something that could cause crashes tell me
I'm near to the solution.
I removed @on_main_thread (that crashes many scripts i already worked on and worked with previous beta) and i tried to experiment with ObjCBlocks, always with a crash. So downloaded the example in the docs about the blocks. Guess what? It Crashes! The crash definitely has to do with blocks
Hope this helps solving the bug,
Filippo
I'll do some more testing. It might have to do with different build settings in the TestFlight version vs. my local development build β after all, the code I posted definitely works here, and I don't think hardware differences are responsible for this (iPad Air 1 vs. 2 aren't that different).
I think this particular use case is possible to do without blocks (using a delegate instead), but it would still be nice if I could get those to work reliably.
Thanks :-)
Did some (more and more) testing with the example file and found that maybe the line 14 (where the handler is called) is responsible for the crash
I can run the example block code (sorting function) from the documentation. My device is also a iPad Air 2.
The RPScreenRecorder did NOT run but it was due to a different error. The replaykit was not created successfully. The bundleWithPath_ method returned a None for me.
Your error is there because you have iOS 8. ReplayKit is a framework of iOS 9.
Dunno about the example, maybe is some iOS 9 bug
@omz I was wrong, the line that crashes the app is line 14, where you call the handler. Anyway @on_main_thread crashes too for me. Remember i am on iPad Air 2 WiFi iOS 9 beta 5
Ok, @omz in the meantime can you show me how to do with delegates, please? :-)
Would be much appreciated
@filippocld said:
Ok, @omz in the meantime can you show me how to do with delegates, please? :-)
Would be much appreciated
Turns out that I was wrong about that. It's not possible to do this without blocks.
I don't really have any idea why this doesn't work for you, to be honest. I installed the latest beta directly from TestFlight (the exact same build you have) on an iPad Air 1 that has iOS 9 beta 5 installed, and it works just fine. I just can't think of a reason why it wouldn't work on an iPad Air 2 right now.
Do you have a way to see my crash logs and maybe understand the problem?
I mean, it happens everytime i call an handler in every function, it shouldn't be so difficult.
I only get aggregate crash reports, and they're delayed, so if you could send me one of yours, that might be helpful (Settings app → privacy → diagnostics & usage → diagnostics & usage data). I can't really promise that I can fix this though β as I've mentioned in the docs, the whole ObjCBlock feature is extremely experimental and relies on stuff that isn't really documented anywhere.
I am currently having problems sith crash logs in iOS 9 beta 5, will send them later this week when beta 6 comes out.
Anyway i have a question.
Can you show me the simplest example of : "For blocks that donβt have a return value and no arguments, you can pass a Python function, and itβll be converted to an ObjCBlock automatically."
? Still doing some testing and slowly understanding the mechanics
Shortest example I can think of, though I don't really think it'll work for you if other blocks crash...
from objc_util import *
NSOperationQueue = ObjCClass('NSOperationQueue')
NSBlockOperation = ObjCClass('NSBlockOperation')
def foobar():
print 'test'
q = NSOperationQueue.mainQueue()
op = NSBlockOperation.blockOperationWithBlock_(foobar)
q.addOperation_(op)
I"m becoming crazy π±. It crashed -.-
Until i can send you the logs i can only say you that block.invoke() crashes the app and that @on_main_thread does it too :-/
Could anyone else with an iPad Air 2 test this?
Unfortunately I don't have such a device here. As the OS I'm testing on is the same, I can't think of anything else that could be different, apart from the actual hardware... I don't suppose your device is jailbroken? (don't think that's possible on iOS 9, but I don't really follow this closely).
The crashes with on_main_thread surprise/worry me more than those with blocks, to be honest. With the blocks, I know that what I'm doing is a total hack, but the on_main_thread stuff should be pretty standard, and uses documented APIs...
What exactly is the problem with the crash reports btw?
Device is not jailbroken, True statement( if it changes something)is off.
For the logs i cant find a Pythonista-date.log but i find LatestCrash-Pythonista and LatestCrash-Pythonista2, but they're both empty Screenshot
@filippocld said:
True statement( if it changes something)is off.
What do you mean by this?
To be honest, I'm not sure the crash reports would help me very much anyway. It's very difficult to fix something that I can't reproduce at all myself. Usually, a crash report helps with reproducing issues, and then fixing them, but from what I've seen so far, I think the problem may be hardware-specific and just not reproducible on what I have here. I might need to get an iPad Air 2 myself, though I'm a bit reluctant to buy one now, given that there will probably be new iPads in less than 2 months...
In Pythonista Settings there is an option called True statement, which i don't know what does, so i left it to No
For the @on_main_thread thing i remember that in the beta before the introduction of the blocks(160022) @on_main_thread was working fine.
Then in beta 160023 you changed something in on_main_thead that caused the crash
From the Beta Release notes of 160023: "on_main_thread()` should be reentrant now (which means that it's possible to nest calls that are executed to the main thread -- while this mostly worked before, there were cases in which it would result in corrupted return values)."
That's very interesting information, thanks!
I think you mean the "True Divisison" setting β that shouldn't make a difference at all, it's just for the interactive console, and determines whether something like 5/2 evaluates to 2 or 2.5.
Oh, then that's useful :-) thanks
I just ordered an iPad Air 2 that I'll pick up later today. I'm curious if the issue is reproducible, though I'm really not sure if I can fix it, even if it is β it might be too low-level... In any case, it'll be useful to test the new split-screen stuff in iOS 9 as well...
Good! Hope will fix both the crashes or at least one of them.
I am kinda angry when i make a iOS 9 api scripts(Replaykit,Search Apis,Touch id etc.) and cant use it because blocks crash and on main thread crashes too
Okay, I have the new iPad set up for development, and it really seems like this is a hardware-specific issue. I can at least reproduce your crashes now... haven't really investigated this much further yet, just wanted to let you know that I don't really need crash reports anymore.
Oh, thanks! Finally im not only the one with theese problems.
Looking forward for more infos.
Thanks in advance
Filippo
I think I've made some progress! :)
It seems that some compiler optimizations were responsible for the crashes. I have no idea why this only happens on the A8X (or why it happens at all, to be honest), but after I've recompiled libffi (the library ctypes is based on) with a lower optimization level, everything seems to work fine on the iPad Air 2.
I'll need to do a little more testing to make sure that this doesn't somehow break things on other devices, but I'm pretty optimistic that I can fix the crashes you've seen with the next build.
This is Fantastic!
Thanks, if all goes well i will seriously enjoy using objcutil!
Waiing for the next build
Thanks in advance,
Filippo
Knowing a fair bit about processor architectures - S/360 from 1964 application code running unchanged on z13 in 2015 :-) - I'm surprised a NEW processor should have problems with instructions that worked before. Maybe the optimisations were timing-dependent and the compiler authors got that wrong.
So I'd expect A8X issues to be more pervasive.
But we live and learn.
@MartinPacker This is very strange, indeed.
@omz Did you make any progress?
Turns out it isn't quite as easy as I thought... :/
I wanted to release a new beta yesterday, but then I did some final testing with the build I actually uploaded to TestFlight, and while it worked totally fine when testing in Xcode, it turned out that the TestFlight exhibited the very same crashes I had before... :/
Release builds have a slightly different configuration in Xcode, so I've tried a lot of things to make the release build behave like the debug build, but I've already spent hours with this, and haven't found out what causes the different behavior so far. I'm still somewhat optimistic that I'll be able to sort this out eventually, but it's probably going to take a bit longer than I expected...
No, I believed! :-(
Quote:
"The biggest difference between these is that: In a debug build the complete symbolic debug information is emitted to help while debugging applications and also the code optimization is not taken into account. While in release build the symbolic debug info is not emitted and the code execution is optimized. Also, because the symbolic info is not emitted in a release build, the size of the final executable is lesser than a debug executable.
One can expect to see funny errors in release builds due to compiler optimizations or differences in memory layout or initialization. These are ususally referred to as Release - Only bugs :)
Release configuration by default uses different code optimization than Debug configuration, so some code lines can be optimized and skipped
You can check/change configurations at Target -> Build Settings -> search for Optimization Level"
My favorite problem with optimized builds (in Linux) is that I forget to mark a variable as volatile . Works for debug builds, but in optimized builds the compiler often holds values in registers, and voila the update from a different thread gets lost.
Maybe its is something like this.
Georg
@omz So, I installed the new build and IT WORKS, YES!
Can you tell me how did you achieve that?
Thanks for your help, pythonista is the most powerful and useful app ever with objc integration π.
One last thing: what is restype for?
One last thing: what is restype for?